Чому PostgreSQL виконує послідовне сканування на індексованому стовпчику?


150

Дуже простий приклад - одна таблиця, один індекс, один запит:

CREATE TABLE book
(
  id bigserial NOT NULL,
  "year" integer,
  -- other columns...
);

CREATE INDEX book_year_idx ON book (year)

EXPLAIN
 SELECT *
   FROM book b
  WHERE b.year > 2009

дає мені:

Seq Scan on book b  (cost=0.00..25663.80 rows=105425 width=622)
  Filter: (year > 2009)

Чому він НЕ виконує сканування індексу? Що я пропускаю?

Відповіді:


222

Якщо SELECT повертає більше ніж приблизно 5-10% усіх рядків таблиці, послідовне сканування відбувається набагато швидше, ніж індексне сканування.

Це пояснюється тим, що для сканування індексу потрібно кілька операцій вводу-виводу для кожного рядка (шукайте рядок в індексі, потім витягайте рядок з купи). Тоді як послідовне сканування вимагає лише одного вводу-виводу для кожного рядка - або навіть менше, тому що блок (сторінка) на диску містить більше одного рядка, тож більше однієї рядки можна отримати за одну операцію вводу-виводу.

Btw: це справедливо і для інших СУБД - деякі оптимізації як "сканування лише з індексом" відсторонено (але для SELECT * навряд чи така СУБД піде на "сканування тільки з індексом")


12
5-10% залежить від пари параметрів конфігурації та зберігання даних. Це не важке число.
Френк Хайкенс

6
@Frank: тому я сказав "приблизно" :) Але дякую, що вказав на це
a_horse_with_no_name

5
Крім того, послідовне сканування може вимагати декількох сторінок із купи одночасно, і попросити ядро ​​отримати наступний фрагмент, поки воно працює на поточному - сканування індексу отримує одну сторінку одночасно. (Сканація растрових зображень робить компроміс між цими двома. Ви зазвичай бачите, що вони з'являються в плані запитів, недостатньо вибіркових для сканування індексів, але все ще не настільки неселективних, щоб заслужити сканування повної таблиці)
araqnid

4
Цікаве питання - як база даних знає, скільки рядків повернеться запит, не виконуючи його спочатку? Чи зберігає вона таку статистику, як кількість різних значень та розмірів таблиці десь?
Лоран Грегоар

7
@ LaurentGrégoire: так, база даних зберігає статистику щодо кількості рядків та розподілу значень. Детальніше див. У посібнику: postgresql.org/docs/current/static/planner-stats.html
a_horse_with_no_name


0

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

Отже, якщо (кількість записів, які потрібно отримати * 1000) менше загальної кількості записів, індексне сканування буде ефективнішим.


0

@a_horse_with_no_name це досить добре пояснив. Крім того, якщо ви дійсно хочете використовувати сканування індексів, вам, як правило, слід використовувати обмежені діапазони в пункті де. наприклад - рік> 2019 та рік <2020.

Багато разів статистика не оновлюється в таблиці, і це може бути неможливим через обмеження. У цьому випадку оптимізатор не дізнається, скільки рядків має зайняти рік> 2019. Таким чином, він вибирає послідовне сканування замість повних знань. Обмежені перегородки вирішать проблему більшу частину часу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.