Это схема таблицы:
CREATE TABLE IF NOT EXISTS events_table
(
id UUID NOT NULL,
comp_id INT8 NOT NULL,
PRIMARY KEY (id)
);
У нас есть следующий индекс:
CREATE INDEX events_idx ON events_table (comp_id);
И это запрос:
SELECT
table_name.id,
table_name.comp_id,
FROM
schema_name.table_name
WHERE
(table_name.comp_id in Array[?])
Почему сортировка БД в первую очередь:
Gather Merge (cost=116700.30..129758.08 rows=111916 width=122) (actual time=357.017..512.239 rows=295813 loops=1)
-> Sort (cost=115700.28..115840.17 rows=55958 width=122) (actual time=345.202..364.049 rows=98604 loops=3)
Sort Method: external merge Disk: 13760kB
-> Parallel Bitmap Heap Scan on (cost=6311.95..107650.92 rows=55958 width=122) (actual time=51.027..280.405 rows=98604 loops=3)
Planning Time: 0.445 ms
Execution Time: 528.740 ms
(16 rows)
Сначала включено параллельное сканирование кучи растровых изображений?
не следует сортировать, поскольку индекс поддерживает порядок сортировки.
Вы можете попробовать создать временную таблицу (на лету), вставить туда все эти employe_id и использовать JOIN
вместо IN
. Вы также можете попробовать поставить отдельный индекс на employe_id
и удалить его из композиции. Кстати, индексирование метки времени редко бывает хорошей идеей (слишком много записей), вы можете попробовать поместить индекс только в часть даты. Это, скорее всего, уменьшит размер индекса и может помочь планировщику.
PostgreSQL использует индекс idx_balance_state_event_filtering
, а не events_idx
.
Причина, по которой необходима явная сортировка, заключается в том, что сканирование индекса не обязательно возвращает строки в отсортированном порядке. Причиной является IN
состояние.
Если у вас есть индекс с тремя столбцами на (a, b, c)
, следующий запрос не требует явной сортировки, поскольку сканирование индекса возвращает строки в отсортированном порядке:
SELECT ... WHERE a = 42 AND b = 'something' ORDER BY c
Но для этого запроса потребуется явная сортировка:
SELECT ... WHERE a 0 42 AND b IN ('something', 'other') ORDER BY c
Строки будут возвращаться по индексу только кусочно упорядоченными, то есть упорядоченными отдельно для каждого фрагмента, полученного из одного и того же идентификатора сотрудника. Это не то же самое, что общий порядок, указанный в вашем запросе.
PostgreSQL мог бы получить каждую отсортированную часть, а затем чередовать их вместе с помощью чего-то вроде «Merge Append», но никто не удосужился реализовать это. Неясно, как это вообще будет реализовано, поскольку выполнение слияния внутри узла сканирования индекса было бы странным, а перенести границы в какой-то отдельный узел слияния было бы сложно.
Трудно поверить, что это имеет значение, поскольку сортировка занимает меньшую часть общего времени, и это общее время довольно быстрое для начала, учитывая количество возвращаемых строк. Избавление от сортировки может даже замедлить ее, так как тогда вы не получите преимущества ввода-вывода, которое вы можете получить от свойства растрового изображения, подобного последовательному чтению, и распараллеливание также может быть более сложным.
Вы можете получить буквальный режим Merge Append, написав запрос как UNION ALL из группы подзапросов, по одному разу для каждого значения в IN-списке. Вам нужно будет указать ORDER BY для каждого подзапроса, а также для всего UNION ALL, чтобы получить желаемое поведение. Было бы довольно неудобно писать это, и хотя в определенных ситуациях повышение производительности может быть впечатляющим, трудно понять, почему ваш запрос является одной из таких ситуаций.
IN
нарушает это правило, и планировщик запросов игнорирует индекс. Особенно при таком большомIN
условии последовательное сканирование (после сортировки), вероятно, будет более эффективным.