Postgresql
為什麼 ASC 比 DESC 快 100 倍,我該怎麼辦?
我即將理解這一點,但我不明白我需要的修復。以下查詢大約需要一分鐘(給予或接受)來返回 20 條記錄:
explain (analyze, buffers) select "search_docket"."id" FROM "search_docket" WHERE "search_docket"."court_id" = 'delctcompl' ORDER BY "search_docket"."id" desC LIMIT 20; QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------------------- Limit (cost=0.56..2791.05 rows=20 width=4) (actual time=74.950..41059.055 rows=20 loops=1) Buffers: shared hit=38524709 dirtied=10 -> Index Scan Backward using search_docket_pkey on search_docket (cost=0.56..8837737.95 rows=63342 width=4) (actual time=74.947..41059.022 rows=20 loops=1) Filter: ((court_id)::text = 'delctcompl'::text) Rows Removed by Filter: 41862720 Buffers: shared hit=38524709 dirtied=10 Planning time: 0.450 ms Execution time: 41059.233 ms
翻轉排序順序大約需要 60 毫秒:
explain (analyze, buffers) select "search_docket"."id" FROM "search_docket" WHERE "search_docket"."court_id" = 'delctcompl' ORDER BY "search_docket"."id" asC LIMIT 20; QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------- Limit (cost=0.56..2791.05 rows=20 width=4) (actual time=63.701..63.939 rows=20 loops=1) Buffers: shared hit=45783 -> Index Scan using search_docket_pkey on search_docket (cost=0.56..8837737.95 rows=63342 width=4) (actual time=63.698..63.933 rows=20 loops=1) Filter: ((court_id)::text = 'delctcompl'::text) Rows Removed by Filter: 67080 Buffers: shared hit=45783 Planning time: 0.426 ms Execution time: 63.971 ms
你可以看到,在第一個中,它在這裡變得很糟糕:
Rows Removed by Filter: 41862720 Buffers: shared hit=38524709 dirtied=10
以下是表上的索引(省略與此查詢無關的索引):
Indexes: "search_docket_pkey" PRIMARY KEY, btree (id) "search_docket_7a46e69c" btree (court_id) "search_docket_court_id_2d2438b2594e74ba_like" btree (court_id varchar_pattern_ops)
雜念:
- 法院列的基數非常低。它在大約 50M 行中有大約 500 個值。
- 我想我可以在 上添加一個降序索引
court_id
,也許可以解決它,但這似乎不對。- 也許我需要一個多列索引
search_docket.id
和search_docket.court_id
?好像沒了我應該在這裡做一些更好的事情來使索引更好地工作嗎?
這些查詢的理想選擇是在索引中
(court_id, id)
,並且列按該順序排列。它在任何一個方向上都應該非常快。一旦你擁有它,你應該能夠擺脫 court_id 上的普通索引,因為它不再那麼好了。
滿足條件的行(估計在 63000 左右)都有一個高
id
. PostgreSQL 不知道這一點,因此它認為索引掃描在任一方向上都同樣具有吸引力。如果您知道它總是這樣,請使用
DESC
. 如果不是,並且您希望避免對該索引進行索引掃描,請更改ORDER BY
子句以使其與索引表達式不匹配,例如通過添加+ 0
.