Порядок столбцов в составных индексах - PullRequest
0 голосов
/ 30 октября 2018

Я использую составной индекс для таблицы с более чем 13 миллионами записей. index order is (center_code, created_on, status). Center_code и status оба - varchar (100), а не NULL, а create_on - отметка времени без часового пояса.

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

  • Код_центра может иметь 4000 различных значений.
  • Статус может иметь 5 различных значений.
  • Минимальное значение create_on: 2017-12-12 02:00:49.465317+00.

Вопрос в том, что может быть числом уникальных значений для созданного_она? Должен ли я поставить его первым в составном индексе?

Индексирование по столбцу даты работает на основе даты, часа или секунды.

Проблема:

Простой запрос SELECT занимает более 500 мс, используя только этот составной индекс и ничего больше.

Индексы на столе:

Indexes:
    "pa_key" PRIMARY KEY, btree (id)
    "pa_uniq" UNIQUE CONSTRAINT, btree (wbill)
    "pa_center_code_created_on_status_idx_new" btree (center_code, created_on, status)

Запрос:

EXPLAIN ANALYSE 
SELECT "pa"."wbill" 
FROM "pa" 
WHERE ("pa"."center_code" = 'IND110030AAC' 
AND "pa"."status" IN ('Scheduled') 
AND "pa"."created_on" >= '2018-10-10T00:00:00+05:30'::timestamptz);

План запроса:

   Index Scan using pa_center_code_created_on_status_idx_new on pa  (cost=0.69..3769.18 rows=38 width=13) (actual time=5.592..15.526 rows=78 loops=1)
   Index Cond: (((center_code)::text = 'IND110030AAC'::text) AND (created_on >= '2018-10-09 18:30:00+00'::timestamp with time zone) AND ((status)::text = 'Scheduled'::text))
     Planning time: 1.156 ms
     Execution time: 519.367 ms

Любая помощь будет принята с благодарностью.

1 Ответ

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

Условие сканирования индекса:

(((center_code)::text = 'IND110030AAC'::text) AND
  (created_on >= '2018-10-09 18:30:00+00'::timestamp with time zone) AND
 ((status)::text = 'Scheduled'::text))

, но само сканирование индекса превышает (center_code, created_on), а условие status применяется в качестве фильтра.

К сожалению, это не видно из плана выполнения, но это следует из следующего правила:

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

Давайте рассмотрим этот пример (в порядке индекса):

 center_code  | created_on          | status
--------------+---------------------+-----------
 IND110030AAC | 2018-10-09 00:00:00 | Scheduled
 IND110030AAC | 2018-10-09 00:00:00 | Xtra
 IND110030AAC | 2018-10-10 00:00:00 | New
 IND110030AAC | 2018-10-10 00:00:00 | Scheduled
 IND110030AAC | 2018-10-11 00:00:00 | New
 IND110030AAC | 2018-10-11 00:00:00 | Scheduled

Вы увидите, что для запроса нужны 4-я и 6-я строки.

PostgreSQL не может сканировать индекс со всеми тремя условиями, поскольку необходимые строки не расположены рядом друг с другом. Он должен будет сканировать только с первыми двумя условиями, потому что все строки, удовлетворяющие этим, находятся рядом друг с другом.

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

Идеальный индекс будет один на (center_code, status, created_on).

...