2010-11-03 1 views
0

Я довольно новичок в SQL, и я пытаюсь решить, как ускорить сложный SQL-запрос в postgres, возможно, улучшив мое использование индексов. Это запрос:Как я могу ускорить этот SQL-запрос?

SELECT 
    (SELECT ev.code FROM classification_item ci, enumeration_value ev 
     WHERE ev.key_id = :ak_0 
     AND ci.entry_id = t.id AND ci.value_id = ev.id) AS axis_0, 
    (SELECT ev.code FROM classification_item ci, enumeration_value ev 
     WHERE ev.key_id = :ak_1 
     AND ci.entry_id = t.id AND ci.value_id = ev.id) AS axis_1, 
    SUM(t.amount) as amount, 
    (SELECT ev.code FROM classification_item ci, enumeration_value ev 
     WHERE ev.key_id = :key_time_id 
     AND ci.entry_id = t.id AND ci.value_id = ev.id) AS time 
FROM "entry" t 
WHERE t.dataset_id = :dataset_id 
AND t.id IN (SELECT ci.entry_id FROM classification_item ci, enumeration_value ev 
    WHERE ev.key_id = :k_0 
    AND ev.code = :v_0 AND ci.value_id = ev.id) 
GROUP BY time, axis_0, axis_1 

Это в основном схема базы данных (как определено в Пилоны):

table_dataset = Table('dataset', meta.metadata, 
    Column('id', Integer, primary_key=True), 
    ) 
table_entry = Table('entry', meta.metadata, 
    Column('id', Integer, primary_key=True), 
    Column('dataset_id', Integer, ForeignKey('dataset.id')), 
    Column('amount', Float()), 
    ) 
table_classification_item = Table('classification_item', meta.metadata, 
    Column('id', Integer, primary_key=True), 
    Column('entry_id', Integer, ForeignKey('entry.id'), index=True), 
    Column('value_id', Integer, ForeignKey('enumeration_value.id'), index=True) 
) 
table_enumeration_value = Table('enumeration_value', meta.metadata, 
    Column('id', Integer, primary_key=True), 
    Column('key_id', Integer, ForeignKey('key.id'), index=True), 
    Column('code', UnicodeText(), index=True), 
    ) 

И это имеет индексы следующим образом:

"dataset_pkey" PRIMARY KEY, btree (id) 
"entry_pkey" PRIMARY KEY, btree (id) 
"classification_item_pkey" PRIMARY KEY, btree (id) 
"ix_classification_item_entry_id" btree (entry_id) 
"ix_classification_item_value_id" btree (value_id) 
"enumeration_value_pkey" PRIMARY KEY, btree (id) 
"ix_enumeration_value_code" btree (code) 
"ix_enumeration_value_key_id" btree (key_id) 

я упускаю какой-либо очевидный индекс, который ускорит запрос? В частности:

  • Следует ли использовать «кластерные» индексы?
  • Должен ли я также индексировать amount на entry, или это не имеет значения для SUM(t.amount) as amount?

Благодарим за помощь. Я знаю, что это довольно сложный вопрос, поэтому, пожалуйста, скажите, могу ли я сделать что-нибудь, чтобы улучшить его.

------ ОБНОВЛЕНИЕ --------------

The output from EXPLAIN ANALYZE на приведенном выше запросе.

+0

было бы полезно, если вы выкладываете объяснить план –

+1

Как правило, вы всегда должны иметь кластерные индексы. Есть редкие исключения, но они ** действительно ** редки. – JNK

+0

Извините, мне кажется, я немного смущен тем, что на самом деле представляет собой «кластеризованный» индекс. Являются ли индексы, которые у меня выше, фактически сгруппированы? Мне было интересно, могу ли я создать «совместный» индекс по двум клавишам сразу ... – AP257

ответ

0

Что скажет о запросе плана EXPLAIN ANALYZE?

+0

Ah OK, я добавил это - см. Обновление в вопросе. – AP257

1

Если таблица enumeration_value небольшая, то, возможно, вы получите некоторое улучшение, сделав axis_1 и axis_0 в качестве соединения и добавьте дополнительный индекс.

что-то вроде этого (не тестировался)

CREATE INDEX idx_ci_vi_ei ON classification_item(value_id, entry_id); 

CREATE INDEX idx_id_ki ON enumeration_value(id, key_id); 

SELECT 
    ci_0.code AS axis_0, 
    ci_1.code AS axis_1, 
    SUM(t.amount) as amount, 
    ci_t.code AS time 
FROM 
    "entry" t, 
    (SELECT ev.code FROM classification_item ci, enumeration_value ev 
     WHERE ev.key_id = :ak_0 AND ci.value_id = ev.id) ci_0, 
    (SELECT ev.code FROM classification_item ci, enumeration_value ev 
     WHERE ev.key_id = :ak_1 AND ci.value_id = ev.id) ci_1, 
    (SELECT ev.code FROM classification_item ci, enumeration_value ev 
     WHERE ev.key_id = :key_time_id AND ci.value_id = ev.id) ci_t 
WHERE t.dataset_id = :dataset_id 
AND t.id IN (SELECT ci.entry_id FROM classification_item ci, enumeration_value ev 
    WHERE ev.key_id = :k_0 
    AND ev.code = :v_0 AND ci.value_id = ev.id) 
AND t.id = ci_0.entry_id AND t.id = ci_1.entry_id AND t.id = ci_t.entry_id 
GROUP BY time, axis_0, axis_1 
+0

enumeration_value большой, увы ... так же, как и entry_regory_item. только набор данных и ключ малы. – AP257

+0

может продолжаться второй 'CREATE INDEX'. попробуйте –