Я работаю с набором данных HackerNews в Postgres.Есть около 17 миллионов строк, из них около 14,5 миллионов комментариев и около 2,5 миллионов историй.Есть очень активный пользователь по имени "rbanffy", у которого есть 25k представлений, о равных разделенных историях / комментариях.Оба «по» и «тип» имеют отдельные индексы.
У меня есть запрос:
SELECT *
FROM "hn_items"
WHERE by = 'rbanffy'
and type = 'story'
ORDER BY id DESC
LIMIT 20 OFFSET 0
, который выполняется быстро (используется индекс «по»).Если я изменю тип на «комментарий», то он будет очень медленным.Из объяснения, он не использует ни один из индексов и выполняет сканирование.
Limit (cost=0.56..56948.32 rows=20 width=1937)
-> Index Scan using hn_items_pkey on hn_items (cost=0.56..45823012.32 rows=16093 width=1937)
Filter: (((by)::text = 'rbanffy'::text) AND ((type)::text = 'comment'::text))
Если я изменю запрос на type||''='comment'
, он будет использовать индекс 'by' и быстро выполнится.
Почему это происходит?Из https://stackoverflow.com/a/309814/214545 я понимаю, что необходимость такого взлома означает, что что-то не так.Но я не знаю что.
РЕДАКТИРОВАТЬ:
Это объяснение для type = 'story'
Limit (cost=72553.07..72553.12 rows=20 width=1255)
-> Sort (cost=72553.07..72561.25 rows=3271 width=1255)
Sort Key: id DESC
-> Bitmap Heap Scan on hn_items (cost=814.59..72466.03 rows=3271 width=1255)
Recheck Cond: ((by)::text = 'rbanffy'::text)
Filter: ((type)::text = 'story'::text)
-> Bitmap Index Scan on hn_items_by_index (cost=0.00..813.77 rows=19361 width=0)
Index Cond: ((by)::text = 'rbanffy'::text)
РЕДАКТИРОВАТЬ: ОБЪЯСНИТЬ (АНАЛИЗИТЬ, БУФЕРЫ)
Limit (cost=0.56..59510.10 rows=20 width=1255) (actual time=20.856..545.282 rows=20 loops=1)
Buffers: shared hit=21597 read=2658 dirtied=32
-> Index Scan using hn_items_pkey on hn_items (cost=0.56..47780210.70 rows=16058 width=1255) (actual time=20.855..545.271 rows=20 loops=1)
Filter: (((by)::text = 'rbanffy'::text) AND ((type)::text = 'comment'::text))
Rows Removed by Filter: 46798
Buffers: shared hit=21597 read=2658 dirtied=32
Planning time: 0.173 ms
Execution time: 545.318 ms
РЕДАКТИРОВАТЬ: ОБЪЯСНИТЬ (АНАЛИЗ, БУФЕРЫ) type='story'
Limit (cost=72553.07..72553.12 rows=20 width=1255) (actual time=44.121..44.127 rows=20 loops=1)
Buffers: shared hit=20137
-> Sort (cost=72553.07..72561.25 rows=3271 width=1255) (actual time=44.120..44.123 rows=20 loops=1)
Sort Key: id DESC
Sort Method: top-N heapsort Memory: 42kB
Buffers: shared hit=20137
-> Bitmap Heap Scan on hn_items (cost=814.59..72466.03 rows=3271 width=1255) (actual time=6.778..37.774 rows=11630 loops=1)
Recheck Cond: ((by)::text = 'rbanffy'::text)
Filter: ((type)::text = 'story'::text)
Rows Removed by Filter: 12587
Heap Blocks: exact=19985
Buffers: shared hit=20137
-> Bitmap Index Scan on hn_items_by_index (cost=0.00..813.77 rows=19361 width=0) (actual time=3.812..3.812 rows=24387 loops=1)
Index Cond: ((by)::text = 'rbanffy'::text)
Buffers: shared hit=152
Planning time: 0.156 ms
Execution time: 44.422 ms
РЕДАКТИРОВАТЬ: последние результаты теста, которые я воспроизводил с помощью запроса type='comment'
, и заметил, изменил ли лимит набольшее число, например 100, использовался индекс by
.Я играл со значениями, пока не обнаружил, что критическое число было 47.Если у меня был предел 47, использовался индекс by
, если у меня был предел 46, это было полное сканирование.Я предполагаю, что число не является магическим, просто является порогом для моего набора данных или какой-то другой переменной, которую я не знаю.Я не знаю, поможет ли это.