Индекс запроса диапазона PostgreSQL - PullRequest
0 голосов
/ 30 октября 2018

Допустим, у меня есть простая таблица в PostgreSQL:

CREATE TABLE bingest.some_data (
      report_date DATE NOT NULL,
      client_id UUID NOT NULL,
      value_1 INT, value_2 INT, value_3 INT,
      value_4 INT, value_5 INT, value_6 INT,
      value_7 INT, value_8 INT, value_9 INT,
      value_10 INT, value_11 INT, value_12 INT,
      value_13 INT, value_14 INT, value_15 INT,
      value_16 INT, value_17 INT, value_18 INT,
      value_19 INT,
PRIMARY KEY (report_date, client_id));

Я хочу, чтобы индекс использовался в следующем запросе

SELECT * FROM some_data WHERE report_date > '2018-10-30';

Для вышеприведенного запроса команда EXPLAIN дает мне

Seq Scan on some_data  (cost=0.00..18.12 rows=217 width=96)
    Filter: (report_date > '2018-10-30'::date)
Planning time: 0.061 ms
Execution time: 0.019 ms

Индекс используется, когда я задаю верхнюю и нижнюю границы

SELECT * FROM some_data WHERE report_date > '2018-10-30' AND < '2019-10-30'

Для этого EXPLAIN дает следующий вывод:

Bitmap Heap Scan on some_data  (cost=4.18..11.30 rows=3 width=96)
    Recheck Cond: ((report_date > '2018-10-30'::date) AND (report_date < '2019-10-30'::date))
        ->  Bitmap Index Scan on some_data_pkey  (cost=0.00..4.18 rows=3 width=0)
                Index Cond: ((report_date > '2018-10-30'::date) AND (report_date < '2019-10-30'::date))
Planning time: 0.072 ms
Execution time: 0.027 ms

У меня еще нет данных, но я хочу подготовить правильные индексы для этой таблицы.

Ответы [ 2 ]

0 голосов
/ 30 октября 2018

При пустой таблице любое обсуждение настройки производительности является теоретическим. Чтобы действительно что-то знать наверняка, вам нужно поместить много данных в таблицу и сделать эти данные такими же реалистичными, как и набор производственных данных, который вы можете разумно придумать.

Тем не менее, на теорию ...

Таблица сканирования по сравнению с индексом

При пустой таблице наиболее эффективным планом выполнения обычно будет полное сканирование таблицы. Зачем? Начальные затраты / накладные расходы на полный комплект очень низкие.

Использование индекса имеет высокие накладные расходы (то есть базовую стоимость простого поиска независимо от того, что найдено), но чрезвычайно низкую стоимость на строку. Полное сканирование таблицы имеет чрезвычайно низкую нагрузку при максимальной стоимости за строку. С учетом сказанного есть два практических правила:

  • Чем меньше таблица, тем менее полезен индекс.
  • Чем более выборочный индексный поиск, тем он полезнее. Поиск по индексу, который затем соответствует 90% строк в таблице, очень неэффективен, и СУБД, как правило, достаточно умны, чтобы этого не делать.

Оценки и статистика

Учитывая приведенные выше практические правила, для того чтобы СУБД могла решить, какой план является наиболее эффективным, ей необходимо знать некоторые детали данных, в частности, количество строк в таблице и количество строк в запросе. скорее всего, совпадет.

Мы получаем подвох-22, потому что ему нужно запросить данные, чтобы выяснить, сколько данных вернется, чтобы он мог выбрать наиболее эффективный план запроса.

Таким образом, все это работает так, что СУБД, как и Postgres, хранит статистику о данных, которые планировщик запросов может использовать. Эти статистические данные точны в определенные моменты времени и являются оценочными. Пример статистики:

  1. Приблизительное количество строк для таблицы
  2. Для индекса приблизительное количество строк для каждого ключа
  3. Частота определенных значений в столбце

Опять же, помните, что это оценки. Для Postgres гарантировать точность статистики всегда очень дорого, но нам не нужна высокая точность при выборе плана выполнения. Разница между таблицей из 1 строки и таблицей из 2 строк несущественна. Но таблица с 1 строкой или таблица с миллионами строк или таблица с миллионами строк имеют большое значение.

Хорошее чтение здесь: https://www.postgresql.org/docs/9.6/static/planner-stats.html

Краткое описание

Учитывая все вышесказанное, Postgres, вероятно, точно не знает, сколько строк в вашей таблице, но знает, что она мала. Поэтому пороговое значение для использования индекса высокое, поэтому ваш первый запрос выполняет сканирование таблицы. Со второй проверкой даты, вероятно, будет вычислено, что запрос будет соответствовать меньшему количеству строк, когда он проверяет индекс первичного ключа, поэтому он идет для индекса.

0 голосов
/ 30 октября 2018

Если таблица полностью пуста, PostgreSQL оценивает, что она содержит 10 страниц (см. estimate_rel_size в src/backend/optimizer/util/plancat.c).

Это так, чтобы мы не получили катастрофических недооценок, если таблица содержит несколько строк и еще не была автовакуумирована.

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

Чтобы проверить, можно ли использовать индекс , отключите enable_seqscan и объясните запрос. Если он по-прежнему выбирает дорогостоящее последовательное сканирование, он делает это, потому что не может использовать индекс.

...