tl;dr Трябва да добавите индекс към item_id
. „Черната магия“ на индексирането на Postgres е разгледана в 11. Индекси
.
Имате съставен индекс на (topic_id, item_id)
и редът на колоните е важен. Postgres може да използва това за индексиране на заявки за topic_id
, заявки към topic_id
и item_id
, но не (или по-малко ефективно) item_id
сам.
От 11.3. Многоколонни индекси ...
-- indexed
select *
from topics_items
where topic_id = ?
-- also indexed
select *
from topics_items
where topic_id = ?
and item_id = ?
-- probably not indexed
select *
from topics_items
where item_id = ?
Това е така, защото съставен индекс като (topic_id, item_id)
първо съхранява идентификатора на темата, след това идентификаторите на елемент, които също имат този идентификатор на тема. За да търси ефективно идентификатор на елемент в този индекс, Postgres трябва първо да стесни търсенето с идентификатор на тема.
Postgres може обръща индекс, ако смята, че си струва усилието. Ако има малък брой възможни идентификатори на теми и голям брой възможни идентификатори на индекси, той ще търси идентификатора на индекса във всеки идентификатор на тема.
Да приемем например, че имате 10 възможни идентификатора на теми и 1000 възможни идентификатора на артикул и вашия индекс (topic_id, index_id)
. Това е като да имате 10 ясно етикетирани кофи с ID на тема, всяка с 1000 ясно обозначени кофи с ID на елемент вътре. За да стигне до кофите с идентификатори на артикули, трябва да погледне във всяка кофа с идентификатор на тема. За да използвате този индекс при where item_id = 23
Postgres трябва да търси във всяка от 10-те кофи с ID на тема всички кофи с ID на елемент 23.
Но ако имате 1000 възможни идентификационни номера на теми и 10 възможни идентификационни номера на артикули, Postgres ще трябва да търси кофи с 1000 идентификационни номера на теми. Най-вероятно вместо това ще направи пълно сканиране на таблицата. В този случай бихте искали да обърнете индекса си и да го направите (item_id, topic_id)
.
Това зависи до голяма степен от наличието на добра статистика на таблицата, което означава да се уверите, че автоматичното вакуумиране работи правилно.
Така че можете да се измъкнете с един индекс за две колони, ако една колона има много по-малко променливост от друга.
Postgres може също да използва множество индекси, ако смята, че ще накара заявката да се изпълни по-бързо
. Например, ако сте имали индекс на topic_id
и индекс на item_id
, то може използвайте и двата индекса и комбинирайте резултатите. Например where topic_id = 23 or item_id = 42
може да използва индекса topic_id за търсене на тема ID 23 и индекса item_id за търсене на елемент ID 42, след което да комбинира резултатите.
Това обикновено е по-бавно от наличието на съставен (topic_id, item_id)
индекс. Освен това може да бъде по-бавно от използването на единичен индекс, така че не се изненадвайте, ако Postgres реши да не използва множество индекси.
Като цяло, за b-дървовидни индекси, когато имате две колони, имате три възможни комбинации.
- a + b
- а
- б
И имате нужда от два индекса.
- (a, b) -- a и a + b
- (b) – b
(a, b)
обхваща и двете търсения за a и a + b. (b)
корици, търсещи b
.
Когато имате три колони, имате седем възможни комбинации.
- a + b + c
- a + b
- a + c
- а
- b + c
- б
- c
Но имате нужда само от три индекса.
- (a, b, c) -- a, a + b, a + b + c
- (b, c) -- b, b + c
- (c, a) -- c, c + a
Вероятно обаче всъщност искате да избегнете наличието на индекс в три колони. Често е по-бавно . Това, което всъщност искате, е това.
- (a, b)
- (b, c)
- (c, a)
Четенето от индекс е по-бавно от четенето от таблицата. Искате вашите индекси да намалят броя на редовете, които трябва да бъдат прочетени, но не искате Postgres да трябва да сканира повече индекси от необходимото.