计划器未使用索引顺序使用CTE对记录进行排序

问题描述 投票:1回答:2

我正在尝试按条件以相同的顺序将一些id传递到排序索引的子句中,但是查询计划器在执行索引搜索后显式对数据进行排序。以下是我的查询。

  1. 生成临时表。

    SELECT a.n/20 as n, md5(a.n::TEXT) as b INTO temp_table 
    From generate_series(1, 100000) as a(n);
    
  2. 创建索引

    CREATE INDEX idx_temp_table ON temp_table(n ASC, b ASC);
    
  3. 在下面的查询中,计划程序使用索引排序,并且未明确对数据进行排序。(预期)

    EXPLAIN ANALYSE
    SELECT * from 
    temp_table WHERE n = 10
    ORDER BY  n, b
    limit 5;
    

查询计划

QUERY PLAN Limit  (cost=0.42..16.07 rows=5 width=36) (actual time=0.098..0.101 rows=5 loops=1)   
          ->  Index Only Scan using idx_temp_table on temp_table  (cost=0.42..1565.17 rows=500 width=36) (actual time=0.095..0.098 rows=5 loops=1)
            Index Cond: (n = 10)
            Heap Fetches: 5 Planning time: 0.551 ms Execution time: 0.128 ms
  1. 但是当我使用cte的一个或多个id并将它们传递给子句时,计划程序仅使用索引来获取值,但之后会对其进行显式排序(不期望)。

    EXPLAIN ANALYSE
    WITH cte(x) AS (VALUES (10))
    SELECT * from temp_table 
    WHERE n IN ( SELECT x from cte)
    ORDER BY  n, b
    limit 5;
    

    然后计划者使用以下查询计划

查询计划

QUERY PLAN
Limit  (cost=85.18..85.20 rows=5 width=37) (actual time=0.073..0.075 rows=5 loops=1)
  CTE cte
    ->  Values Scan on "*VALUES*"  (cost=0.00..0.03 rows=2 width=4) (actual time=0.001..0.002 rows=2 loops=1)
  ->  Sort  (cost=85.16..85.26 rows=40 width=37) (actual time=0.072..0.073 rows=5 loops=1)
        Sort Key: temp_table.n, temp_table.b
        Sort Method: top-N heapsort  Memory: 25kB
        ->  Nested Loop  (cost=0.47..84.50 rows=40 width=37) (actual time=0.037..0.056 rows=40 loops=1)
              ->  Unique  (cost=0.05..0.06 rows=2 width=4) (actual time=0.009..0.010 rows=2 loops=1)
                    ->  Sort  (cost=0.05..0.06 rows=2 width=4) (actual time=0.009..0.010 rows=2 loops=1)
                          Sort Key: cte.x
                          Sort Method: quicksort  Memory: 25kB
                          ->  CTE Scan on cte  (cost=0.00..0.04 rows=2 width=4) (actual time=0.004..0.005 rows=2 loops=1)
              ->  Index Only Scan using idx_temp_table on temp_table  (cost=0.42..42.02 rows=20 width=37) (actual time=0.012..0.018 rows=20 loops=2)
                    Index Cond: (n = cte.x)
                    Heap Fetches: 40
Planning time: 0.166 ms
Execution time: 0.101 ms
  1. [我试图在传递where子句中的id时进行显式排序,以便保持id的排序顺序,但计划程序仍显式排序]]

    EXPLAIN ANALYSE
    WITH cte(x) AS (VALUES (10))
    SELECT * from temp_table 
    WHERE n IN ( SELECT x from cte)
    ORDER BY  n, b
    limit 5;
    
  2. 查询计划

QUERY PLAN
Limit  (cost=42.62..42.63 rows=5 width=37) (actual time=0.042..0.044 rows=5 loops=1)
  CTE cte
    ->  Result  (cost=0.00..0.01 rows=1 width=4) (actual time=0.000..0.000 rows=1 loops=1)
  ->  Sort  (cost=42.61..42.66 rows=20 width=37) (actual time=0.042..0.042 rows=5 loops=1)
        Sort Key: temp_table.n, temp_table.b
        Sort Method: top-N heapsort  Memory: 25kB
        ->  Nested Loop  (cost=0.46..42.28 rows=20 width=37) (actual time=0.025..0.033 rows=20 loops=1)
              ->  HashAggregate  (cost=0.05..0.06 rows=1 width=4) (actual time=0.009..0.009 rows=1 loops=1)
                    Group Key: cte.x
                    ->  Sort  (cost=0.03..0.04 rows=1 width=4) (actual time=0.006..0.006 rows=1 loops=1)
                          Sort Key: cte.x
                          Sort Method: quicksort  Memory: 25kB
                          ->  CTE Scan on cte  (cost=0.00..0.02 rows=1 width=4) (actual time=0.003..0.003 rows=1 loops=1)
              ->  Index Only Scan using idx_temp_table on temp_table  (cost=0.42..42.02 rows=20 width=37) (actual time=0.014..0.020 rows=20 loops=1)
                    Index Cond: (n = cte.x)
                    Heap Fetches: 20
Planning time: 0.167 ms
Execution time: 0.074 ms

谁能解释为什么计划者对数据使用显式排序?有没有一种方法可以使计划程序使用索引排序顺序,以便可以保存记录上的其他排序。在生产中,我们有类似的案例,但是我们选择的规模太大,但是只有少量记录需要分页获取。谢谢您的期待!

我正在尝试按条件以相同的顺序将一些id传递到排序索引的子句中,但是查询计划器在执行索引搜索后显式对数据进行排序。以下是我的...

sql postgresql sorting sql-order-by postgresql-9.6
2个回答
0
投票

优化程序不知道CTE已排序。如果您扫描索引中的多个值并使用ORDER BY,则PostgreSQL将始终进行排序。


0
投票

实际上是由计划者做出的决定,其中包含更大的values()集,Postgres切换到智能计划,并在合并之前完成排序。

© www.soinside.com 2019 - 2024. All rights reserved.