#sql #postgresql #performance
#sql #postgresql #Производительность
Вопрос:
У меня есть запрос, который я хочу выполнить как можно быстрее. Это:
explain analyze
select
*
from
rtsepezocoav_102999 av
join rtco_102097 c on
c.lo_id = av.co_id
where
av.ad_id = 335
and av.pe_id = 70
and av.se_id = 12
Я получаю следующий план:
Hash Join (cost=1238.88..3275.61 rows=40581 width=80) (actual time=10.341..47.707 rows=41238 loops=1)
Hash Cond: (av.co_id = c.lo_id)
-> Bitmap Heap Scan on rtsepezocoav_p_70_103719 av (cost=868.38..2798.54 rows=40581 width=68) (actual time=4.550..17.615 rows=41238 loops=1)
Recheck Cond: ((se_id = 12) AND (ad_id = 335))
Filter: (pe_id = 70)
Heap Blocks: exact=360
-> Bitmap Index Scan on rtsepezocoav_p_70_103719_se_id_ad_id_idx (cost=0.00..858.23 rows=40581 width=0) (actual time=4.450..4.450 rows=41238 loops=1)
Index Cond: ((se_id = 12) AND (ad_id = 335))
-> Hash (cost=204.67..204.67 rows=13267 width=12) (actual time=5.759..5.759 rows=13267 loops=1)
Buckets: 16384 Batches: 1 Memory Usage: 699kB
-> Seq Scan on rtco_102097 c (cost=0.00..204.67 rows=13267 width=12) (actual time=0.009..2.125 rows=13267 loops=1)
Planning Time: 0.515 ms
Execution Time: 51.100 ms
Я думаю, это не страшно. Но фактический запрос более сложный я буду запускать этот запрос параллельно на разных сегментах. Итак, я действительно сосредоточен на том, чтобы получить это молниеносно. Есть ли что-то, чего мне не хватает, или это просто предел postgres? На мой взгляд, это кажется немного «медленным» — объединять 40 тысяч записей (rtsepezocoav_p_70_103719) с 10 тысячами записей (rtco).
rtsepezocoav_p_70_103719 имеет индексы: (ad_id, pe_id, se_id) (ad_id, se_id) (co_id)
rtco имеет индекс (lo_id)
Одна из первых вещей, которая приходит на ум, почему он использует «Сканирование кучи растровых изображений» вместо сканирования только по индексу?
Когда я делаю:
explain analyze select 1 from rtsepezocoav_102999 av
Я получаю сканирование только по индексу, и оно занимает 15 мс (также кажется длинным).
Я на Postgres 12.
Комментарии:
1. Он возвращает что-то вроде 40 тыс. строк. Это займет время.
2. Время выполнения быстрее, чем вы моргаете глазом. Сколько именно МС вы ожидаете и чего пытаетесь достичь?
3. Можете ли вы показать нам план, созданный с помощью
explain (analyze, buffers, timing)
и запущенныйset track_io_timing=on;
перед этим (для этого вам потребуется доступ суперпользователя). Вы также можете попробовать поиграть с порядком столбцов для индекса,rtsepezocoav_p_70_103719
возможно, помещенногоpe_id
в качестве первого столбца. Какую версию Postgres вы используете?4. есть ли у rtsepezocoav_102999 индекс в co_id? как правило, вы хотели бы, чтобы индексировались обе стороны условия объединения
5. Вы не сможете легко получить сканирование только по индексу, если вы
SELECT *
.
Ответ №1:
Я думаю, что вы могли бы добавить индекс на co_id
. У вас есть индексы во всех идентификаторах в where, но при объединении у вас есть индекс только на 1 стороне объединения.
rtco has index on (lo_id)
rtsepezocoav_p_70_103719 has indexes on: (ad_id, pe_id, se_id) => this one should have index on co_id
При отсутствии индекса в co_id он в конечном итоге выполняет последовательное сканирование rtsepezocoav_p_70_103719
таблицы при объединении
Комментарии:
1. Упс, я пропустил сообщить о некоторых других индексах, которые у меня есть, включая тот, который вы упомянули. Я обновлю вопрос.
2. В таком случае, это всего лишь мысль, но, возможно, если вы сначала отфильтруете таблицу rtsepezocoav_p_70_103719 с помощью «где av.ad_id = 335 и av.pe_id = 70 и av.se_id = 12, а затем выполните объединение с меньшим количеством строк на этой стороне, это могло бы помочь. В этот момент запрос сначала выполняет from , затем join, а затем where, так что в конечном итоге он выполняет join с некоторыми строками, которые не имеют отношения к делу, а затем использует where для фильтрации соответствующих результатов
Ответ №2:
Спасибо за советы, но, честно говоря, я думаю, что я действительно выполнял преждевременную оптимизацию…