Каков наилучший подход к индексированию в Postgres (или любой другой базе данных SQL)

У меня есть следующий запрос:

SELECT
    id,
    RANK() OVER (
      PARTITION BY user_id
      ORDER BY
        effective_date <= '${date}' DESC,
        effective_date DESC,
        created_at DESC
    ) AS rank
FROM $table WHERE company_id = $companyId AND effective_date <= $date;

Я хочу добавить индекс в таблицу, чтобы ускорить выполнение запроса. Я предполагаю, что наличие составного индекса (company_id, effect_date) поможет. Однако я также хотел добавить столбец user_id как часть индекса.

Итак, мой вопрос: следует ли мне использовать один индекс (company_id, effect_date, user_id)? Поможет ли использование userId в качестве последней части составного индекса производительности PARTITION BY user_id ИЛИ мне следует добавить отдельный индекс только для UserID? Или это не имеет значения, так как это вообще не поможет?

Также стоит упомянуть: есть также несколько запросов, которые не используют ранги и разделы, а фильтрwhere применяется только к Company_id и user_id. В этом случае лучшим вариантом индекса будет (company_id, user_id). Однако в большинстве случаев используется первый запрос, поэтому повышение производительности этого запроса будет наиболее важной задачей.

Вывод EXPLAIN (ANALYZE, VERBOSE, BUFFERS, SETTINGS) при наличии индекса (company_id, effect_date, user_id):

WindowAgg  (cost=35.39..36.91 rows=55 width=29) (actual time=0.396..0.596 rows=56 loops=1)
  Output: id, rank() OVER (?), ((effective_date <= '2025-05-30'::date)), effective_date, created_at, user_id
  Buffers: shared hit=5
  ->  Sort  (cost=35.39..35.53 rows=55 width=21) (actual time=0.342..0.352 rows=56 loops=1)
        Output: ((effective_date <= '2025-05-30'::date)), effective_date, created_at, user_id, id
        Sort Key: user_role.user_id, ((user_role.effective_date <= '2025-05-30'::date)) DESC, user_role.effective_date DESC, user_role.created_at DESC
        Sort Method: quicksort  Memory: 29kB
        Buffers: shared hit=5
        ->  Bitmap Heap Scan on public.user_role  (cost=4.84..33.80 rows=55 width=21) (actual time=0.223..0.273 rows=56 loops=1)
              Output: (effective_date <= '2025-05-30'::date), effective_date, created_at, user_id, id
              Recheck Cond: ((user_role.company_id = 47) AND (user_role.effective_date <= '2025-05-30'::date))
              Heap Blocks: exact=3
              Buffers: shared hit=5
              ->  Bitmap Index Scan on user_role__company_id_effective_date_user_id_idx  (cost=0.00..4.83 rows=55 width=0) (actual time=0.170..0.171 rows=56 loops=1)
                    Index Cond: ((user_role.company_id = 47) AND (user_role.effective_date <= '2025-05-30'::date))
                    Buffers: shared hit=2
Settings: jit = 'off'
Planning Time: 0.959 ms
Execution Time: 0.785 ms

Пробовали ли вы добавлять разные индексы, а затем проверять план выполнения запроса для каждого из них? Это отличный способ исследовать и учиться. Если вы столкнетесь с поведением, которое отличается от того, что вы ожидаете, вы можете задать гораздо более конкретный вопрос.

user1191247 30.05.2024 12:48

@user1191247 user1191247 да, я протестировал несколько вариантов, во всех случаях я получаю одинаковую производительность, и когда я запускаю запрос с анализом объяснения, я всегда получаю: Ключ сортировки: user_id, ((efficient_date <= '2024-05-30':: date)) DESC, effect_date DESC, create_at DESC" и метод сортировки: быстрая сортировка Память: 29 КБ" фильтрация в предложенииwhere всегда одинакова. Однако я не знаю, есть ли какая-либо польза от наличия user_id в индексе. Также может случиться так, что моя выборка данных недостаточно велика, чтобы протестировать запросы и увидеть разницу в производительности.

rb27 30.05.2024 13:25

Не могли бы вы поделиться результатами explain(analyze, verbose, buffers, settings) по этому запросу? Обычным текстом.

Frank Heikens 30.05.2024 16:01

@FrankHeikens Я обновил описание, указав результаты запроса.

rb27 30.05.2024 18:03
Execution Time: 0.785 ms, это будет близко к совершенству! На данный момент я бы не стал тратить больше времени на этот запрос, он быстрый и, скорее всего, на данный момент достаточно быстрый.
Frank Heikens 30.05.2024 18:36

Он отмечен [mysql]; либо удалите этот тег, либо добавьте EXPLAIN (и т. д.) для этой СУБД.

Rick James 31.05.2024 02:04

@RickJames, заголовок: «Каков наилучший подход к индексированию в Postgres (или любой другой базе данных SQL)». Меня больше интересует знание того, как индекс работает в таком запросе независимо от БД, а не знание конкретного подхода postgres.

rb27 31.05.2024 11:28

Вполне вероятно, что между различными СУБД существуют несовместимые различия в реализации. Я думаю, что это лучше всего.

Rick James 31.05.2024 21:22
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
8
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Нет, добавление user_id в индекс не ускорит этот конкретный запрос.

Поскольку effective_date сравнивается с <, результат сканирования индекса не будет предварительно упорядочен user_id, поэтому оценка оконной функции не принесет пользы. Дополнительный столбец сделает индекс больше и, следовательно, менее эффективным, поэтому, если вы не можете использовать третий столбец индекса для какого-либо другого запроса, не добавляйте его.

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