Чи складний індекс також хороший для запитів у першому полі?


86

Скажімо, у мене є таблиця з полями Aі B. Я регулярно роблю запити на A+ B, тому я створив складений індекс на (A,B). Чи були б лише запити Aповністю оптимізовані складеним індексом?

Крім того, я створив індекс на A, але Postgres все ще використовує складений індекс лише для запитів A. Якщо попередня відповідь позитивна, я думаю, це насправді не має значення, але чому він вибирає складений індекс за замовчуванням, якщо єдиний Aіндекс доступний?


Я спробував встановити для цього невеликий тест. У моєму випадку, однак, індекс з двома стовпцями використовувався лише тоді, коли я скинув один стовпчик, не пов'язаний з тим, який був створений першим. Цікаво, що якщо я спершу створив індекс з двома стовпцями, то в початковому плані було використано біт-карту. Якщо я створив одноколонний індекс, то запустив запит (використано сканування індексу) і скинув новостворений індекс, план, що включає індекс двох стовпців, перейшов на сканування індексу. Дивіться кроки на SQLFiddle
дез

@dezso Цікаво. Де коштують кожен запит?
Лучано

Вартість сканування індексу Bitmap: 107,98, час виконання 43 мс. Індексне сканування одного стовпчика: вартість 8,69, двоколонного: 43,69. Часи виконання не суттєво відрізняються (коливання більше, ніж різниця між ними).
дезсо

@Luciano Чи можете ви показати explain analyzeтекст запиту та запиту?
Крейг Рінгер

Відповіді:


88

Це, безумовно, є. Ми це детально обговорили під цим пов'язаним питанням:

Простір виділяється в кратних розмірах MAXALIGN, що, як правило, становить 8 байт на 64-бітній ОС або (набагато рідше) 4 байти на 32-бітній ОС. Якщо ви не впевнені, перевірте pg_controldata. Це також залежить від типів даних індексованих стовпців (деякі вимагають вирівнювання) і фактичного вмісту.

Індекс на, скажімо, два integerстовпчики (по 4 байти в кожному) зазвичай закінчується таким же великим, як і індекс лише на одному, де ще 4 байти втрачаються на вирівнювання.

У такому випадку дійсно немає недоліків для планувальників запитів використовувати індекс на (a,b)- порівняно з індексом на просто (a). І, як правило, бажано для декількох запитів використовувати один і той же індекс. Шанс, щоб він (або його частини) перебував у (швидкому) кеші, зростає при спільному використанні.

Якщо індекс вже підтримується, інший індекс (a,b)не має сенсу створювати просто, (a)якщо він не є значно меншим. Те ж саме НЕ вірно для (b,a)VS. (a). Щоб отримати докладнішу інформацію, перейдіть за посиланням у першому рядку.

Виходячи з протилежного напрямку, коли вам потрібен додатковий індекс, подібний до цього (a,b), тоді розгляньте можливість скидання наявного індексу просто (a)- якщо можливо. Часто це неможливо, оскільки це індекс ПК або UNIQUEобмеження. Оскільки Postgres 11, ви можете уникнути, просто додавши bдо цього визначення визначення обмеження INCLUDE. Деталі в посібнику.

Або(b,a) замість цього створити новий індекс, щоб просто bдодатково покривати запити . Для лише умов рівності порядок індексних виразів в btree індексах не має значення. Це, однак, при участі в дальності. Побачити:

Можливі недоліки включення додаткових стовпців в індекс, навіть якщо для цього використовується лише простір, втрачений в іншому випадку для вирівнювання прокладки:

  • Щоразу, коли додатковий стовпець оновлюється, індекс також потребує оновлення, що може призвести до збільшення витрат на операції запису та створення більшої кількості індексу.
  • ГОРЯЧІ оновлення (Heap Only Tuple) на столі не можливі під час участі будь-якого стовпчика індексу.

Більше про оновлення HOT:

Як виміряти розміри об'єктів:


1
Чи можете ви розширити це так, що якщо у мене є індекс у стовпці А, і виникає потреба додати складний індекс (A, B), індекс A слід скинути? Якщо повторне використання індексу покращує ефективність кешу, і (A, B) повністю оптимізує A, тоді здається, що додатковий індекс на A витратить простір і потенційно сповільнить речі
jvans

1
@jvans: Загалом правда - з помітними винятками та альтернативами. Я додав абзац, щоб вирішити це.
Ервін Брандштеттер

2

Відповідно до вашого запитання, у вас є таблиця з полями A і B. Якщо у вас запит:

SELECT * FROM [YOUR TBL]
WHERE A='XXXX'

Оптимізатор вибере індекс Composite, щоб уникнути вилучення випадкового доступу!


-4

Це в тому випадку, якщо ви просто використовуєте лише перший присудок.

Він буде виконувати сканування, якщо ви будете використовувати перші стовпці складеного ключа та неключій колонку складеного ключа.

Щоб виправдати це, ви можете просто придумати такі предикати, як цей, а потім нечетковий стовпець:

[A, B] - ваш індекс, [C] - інший стовпець

Щоб використовувати індекс, ви записуєте як:

SELECT
    A,B,C,D,E
FROM 
    test
WHERE
   A=1
AND
   B=B
AND 
   C=3

... чому він вибирає складений індекс за замовчуванням, якщо єдиний індекс A доступний?

Він використовуватиме індекс лише у тому випадку, якщо є один або два предикати [A] Або [A], [B]. Він не буде використовувати його в порядку [B], [A] або [A], [C]. Щоб мати можливість використовувати індекс з додатковим стовпцем [C], вам потрібно застосувати індекс, упорядкувавши предикати як [A], [B] та [C].


2
Чого саме ви досягаєте B=B? Я думаю, що ви нічого не досягаєте, тому я голосую без будь-яких доказів, це оптимізатор не ігнорує
Джек Дуглас

2
B=Bфактично те саме B IS NOT NULL, що, здається, не вимагається. Звичайно, не потрібно використовувати індекс на (a,b).
Ервін Брандштетер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.