Чи може PostgreSQL використовувати нулі у своїх індексах?


10

Я читав цю книгу, яка говорить про це

База даних передбачає, що Indexed_Col НЕ NULL охоплює занадто великий діапазон, щоб бути корисним, тому база даних не буде запускати до індексу з цієї умови.

Я усвідомлюю, що книзі вже більше 10 років, але вона вже виявилася досить корисною - використовуючи інструкції, зібрані зі своїх сторінок, я заробив запит у десять разів.

Далі, працюючи EXPLAIN ANALYZEнад SELECTзапитом, я виявив, що жоден з моїх індексів не використовується, навіть коли за всіма правами вони повинні бути.

Таким чином, моє питання:

Припустимо, що існує таблиця з стовпцем, визначення якої стовпця містить "NOT NULL", і що існує індекс, який охоплює цей стовпець, чи буде цей індекс використаний у запиті тієї таблиці, де стовпці є частиною запиту?

Подібно до:

CREATE TABLE my_table(
a varchar NOT NULL
);

CREATE INDEX ix_my_table ON my_table(a);

SELECT a from my_table;

Відповіді:


9

PostgreSQL, безумовно, може використовувати індекс для IS NOT NULL. Я не бачу припущень планувальника запитів щодо цієї умови.

Якщо нульова частка для стовпця ( pg_statistic.stanullfrac) є достатньо низькою, щоб припустити, що індекс корисно вибірковий для запиту, PostgreSQL використовуватиме індекс.

Я не можу зрозуміти, що ти намагаєшся сказати:

Якщо це правильно, чи я розумію, що індекс у стовпці, визначеному як "NOT NULL", не використовується у запиті, який використовує цей стовпець?

Звичайно, індекс не звикне до IS NOT NULLумови в NOT NULLстовпці. Він завжди збігався б на 100% рядків, тому послідовно майже завжди буде набагато швидше.

PostgreSQL не використовуватиме індекс, якщо індекс не відфільтрує велику частку рядків для запиту. Єдине ймовірне виняток - коли ви запитуєте набір стовпців, охоплених одним індексом, у порядку, що відповідає рівню індексу. Потім PostgreSQL може виконати сканування лише з індексом. Наприклад, якщо на вас є індекс t(a, b, c):

select a, b FROM t ORDER BY a, b, c;

PostgreSQL може використовувати ваш індекс, навіть якщо жодні рядки не відфільтровані, тому що він повинен лише зчитувати індекс і може пропустити читання купи, уникаючи сортування тощо.


Це все вірно з PG 9.0
eradman

1
І навіть у стовпчику, що зводить нанівець, запит із умовою WHERE column IS NOT NULLможе не використовувати індекс, оскільки, як говорить книга: "охоплює занадто великий діапазон, щоб бути корисним". Якщо 90% значень не є нульовими, швидше за все, швидше буде і seqscan.
ypercubeᵀᴹ

Саме так. Це може бути, але лише в тому випадку, якщо велика частина таблиці є нульовою. Часто в цьому випадку частковий індекс все одно є кращим вибором.
Крейг Рінгер

Так. Я намагався сказати, що (наскільки я розумію) частина "охоплює занадто великий діапазон" відноситься до індексу, але щодо конкретного стану, а не до індексу взагалі.
ypercubeᵀᴹ

2
@FuriousFolder Heh, тут занадто багато негативів. PostgreSQL не використовуватиме індекс у NOT NULLстовпці для IS NOT NULLзапиту, якщо цей індекс також не корисний для інших частин WHEREпункту, фільтрів приєднання тощо, або він не підходить для впорядкованого сканування лише для індексу. Іншими словами, він буде повністю ігнорувати зайвим IS NOT NULLна NOT NULLколонці і зробити вибір використання індексу на основі інших деталей. (Див. Редагування, повторне сканування лише для покажчиків).
Крейг Рінгер

2

На додаток до ґрунтовної відповіді Крейга, я хотів додати, що обкладинка книги, на яку ви посилаєтесь, говорить:

Охоплює Oracle, DB2 та SQL Server

Тому я б не вірив, що це є чудовим джерелом порад щодо PostgreSQL, зокрема. Кожен RDBMS може бути напрочуд різним!

Я трохи розгублений у вашому первісному запитанні, але ось приклад, який показує, що розділ книги не на 100% правильний. Щоб уникнути подальшої плутанини, ось весь відповідний параграф, ви можете побачити його в пошуку книг Google .

База даних передбачає, що Indexed_Col НЕ NULL охоплює занадто великий діапазон, щоб бути корисним, тому база даних не буде запускати до індексу з цієї умови. У рідкісних випадках наявність ненульового значення настільки рідко, що сканування діапазону індексу над усіма можливими ненульовими значеннями є вигідним. У таких випадках, якщо ви можете встановити безпечну нижню або верхню межу діапазону всіх можливих значень, ви можете ввімкнути сканування діапазону з умовою, такою як Positive_ID_Column> -1 або Date_Column> TO_DATE ('0001/01/01' , "РРРР / ММ / ДД").

Postgres може фактично (у наступному надуманому випадку) використовувати індекс для задоволення IS NOT NULLзапитів без додавання діапазонів сканування діапазону, як запропоновано Positive_ID_Column > -1. Дивіться коментарі до питань Крейга, чому Postgres вибирає саме цей індекс у даному конкретному випадку, та примітку про використання часткових індексів.

CREATE TABLE bar (a int);
INSERT INTO bar (a) SELECT NULL FROM generate_series(1,1000000);
INSERT INTO bar (a) VALUES (1);
CREATE INDEX bar_idx ON bar (a);

EXPLAIN ANALYZE SELECT * FROM bar WHERE a IS NOT NULL;
                                                QUERY PLAN                                                    
------------------------------------------------------------------------------------------------------------------
 Index Only Scan using bar_idx on bar  (cost=0.42..8.44 rows=1 width=4) (actual time=0.094..0.095 rows=1 loops=1)
   Index Cond: (a IS NOT NULL)
   Heap Fetches: 1
 Total runtime: 0.126 ms
(4 rows)

Це, до речі, Postgres 9.3, але я вважаю, що результати були б приблизно подібними на 9.1, хоча він не використовував би "Сканувати тільки з індексом".

Редагувати: Я бачу, що ви уточнили своє початкове запитання, і вам, мабуть, цікаво, чому Postgres не використовує індекс у простому прикладі, як-от:

CREATE TABLE my_table(
a varchar NOT NULL
);

CREATE INDEX ix_my_table ON my_table(a);

SELECT a from my_table;

Можливо, тому, що у вас немає рядків у таблиці. Тому додайте деякі тестові дані та ANALYZE my_table;.


В описі зазначеної книги (моє наголос): "Автор Дан Тау окреслює метод економії часу, який він розробив для пошуку оптимального плану виконання - швидко та систематично - незалежно від складності SQL або використовуваної платформи бази даних " Також, можливо, ви не помітили №1 питання, а саме те, що стовпець визначений як NOT NULL, а не те, що запит використовує IS NOT NULLяк свій показник. Це в коментарях, на які ви посилалися, але я оновлю питання, щоб включити його.
FuriousFolder

Далі, сама книга є агностичною мовою: єдині частини, що стосуються DMBS, стосуються показу планів запитів, який Postgres робить досить простим :)
FuriousFolder

1
@FuriousFolder стовпець визначається як NOT NULL, але ця частина (у вашому запитанні з книги): "що Indexed_Col НЕ NULL охоплює ..." посилається на умову де, а не на визначення стовпця. Хоча важко бути впевненим, адже це поза контекстом. Можливо, вам слід включити весь (попередній) параграф із книги.
ypercubeᵀᴹ

-1

Ви не опублікували дані запиту чи прикладу. Але найпоширеніші причини, за якими не використовуються індекси, пов'язані з обсягом.

Покажчики схожі на телефонну книгу, яка переводить стовпець у місцеположення рядків. Якщо ви шукаєте лише кілька рядків, є сенс шукати кожен рядок у телефонній книзі, а потім шукати рядок у головній таблиці.

Але для кількох рядків дешевше пропустити телефонну книгу та повторити всі рядки в головній таблиці. На мій досвід, точка відбиття становить близько 100 рядів.


"Індекси - це як телефонна книга, яка переводить стовпець у місцеположення рядків. Якщо ви шукаєте лише кілька рядків, має сенс шукати кожен рядок у телефонній книзі, а потім шукати рядок у головній таблиці." Насправді, індекси - це як менші телефонні книги, які оновлюються в будь-який час, коли оновлена ​​телефонна книга, яку вони індексують. Ви знаєте, що щоразу, коли відкриєте меншу телефонну книгу, ви збираєтесь знайти будь-яку та всю інформацію, яку описує її стан індексації. Наприклад , всі люди назвали «відвертим» на індексного таблиці: CREATE INDEX ix_frank ON people(name) WHERE name ='frank'.
FuriousFolder

Це дозволяє індексувати тільки сканування буде набагато набагато швидше, так як ви можете прочитати всю «меншу телефонну книгу» в пам'ять, що не здійснимо з викладені таблицями багатомільйонних.
FuriousFolder

@FuriousFolder: Ви описуєте сканування лише для індексів. Але ОП каже, що його індекси не використовуються, що не відбудеться, якби сканування, що використовує лише індекс, задовольнило б запит.
Андомар

Andomar ... Я єсмь ОП, ха - ха. Моя мета - саме це; щоб отримати цей запит, використовуйте сканування, призначене лише для покажчика. З тих пір я домігся цього, так як Крейг пояснив , що Postgres є можливість використовувати індекс на колонці , де визначення стовпця включає в себе NOT NULL
FuriousFolder
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.