Postgresql

為什麼 ASC 比 DESC 快 100 倍,我該怎麼辦?

  • April 27, 2021

我即將理解這一點,但我不明白我需要的修復。以下查詢大約需要一分鐘(給予或接受)來返回 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)

雜念:

  1. 法院列的基數非常低。它在大約 50M 行中有大約 500 個值。
  2. 我想我可以在 上添加一個降序索引court_id,也許可以解決它,但這似乎不對。
  3. 也許我需要一個多列索引search_docket.idsearch_docket.court_id?好像沒了

我應該在這裡做一些更好的事情來使索引更好地工作嗎?

這些查詢的理想選擇是在索引中(court_id, id),並且列按該順序排列。它在任何一個方向上都應該非常快。一旦你擁有它,你應該能夠擺脫 court_id 上的普通索引,因為它不再那麼好了。

滿足條件的行(估計在 63000 左右)都有一個高id. PostgreSQL 不知道這一點,因此它認為索引掃描在任一方向上都同樣具有吸引力。

如果您知道它總是這樣,請使用DESC. 如果不是,並且您希望避免對該索引進行索引掃描,請更改ORDER BY子句以使其與索引表達式不匹配,例如通過添加+ 0.

引用自:https://dba.stackexchange.com/questions/290514