Почему БД Postgres сортирует, хотя у меня есть индекс?

Это схема таблицы:

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)

Сначала включено параллельное сканирование кучи растровых изображений?

не следует сортировать, поскольку индекс поддерживает порядок сортировки.

postgresql.org/docs/current/indexes-multicolumn.html говорит: «Точное правило заключается в том, что ограничения равенства для ведущих столбцов, а также любые ограничения неравенства в первом столбце, который не имеет ограничения равенства, будут использоваться для ограничения часть индекса, которая сканируется.". Если я правильно понимаю, ваше условие IN нарушает это правило, и планировщик запросов игнорирует индекс. Особенно при таком большом IN условии последовательное сканирование (после сортировки), вероятно, будет более эффективным.
freakish 06.05.2024 12:39

Вы можете попробовать создать временную таблицу (на лету), вставить туда все эти employe_id и использовать JOIN вместо IN. Вы также можете попробовать поставить отдельный индекс на employe_id и удалить его из композиции. Кстати, индексирование метки времени редко бывает хорошей идеей (слишком много записей), вы можете попробовать поместить индекс только в часть даты. Это, скорее всего, уменьшит размер индекса и может помочь планировщику.

freakish 06.05.2024 14:48

PostgreSQL использует индекс idx_balance_state_event_filtering, а не events_idx.

Laurenz Albe 06.05.2024 14:54
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
75
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Причина, по которой необходима явная сортировка, заключается в том, что сканирование индекса не обязательно возвращает строки в отсортированном порядке. Причиной является 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, чтобы получить желаемое поведение. Было бы довольно неудобно писать это, и хотя в определенных ситуациях повышение производительности может быть впечатляющим, трудно понять, почему ваш запрос является одной из таких ситуаций.

Другие вопросы по теме