事实:
PGSQL 8.4.2,Linux版
我利用表继承
每个表包含300万行
已设置连接列的索引
表格统计(分析,真空分析)是最新的
只使用带有varios分区子表的“node”
递归查询(pg>=8.4)
下面是解释查询:

WITH    RECURSIVE
        rows AS
        (
        SELECT  *
        FROM    (
                SELECT  r.id, r.set, r.parent, r.masterid
                FROM    d_storage.node_dataset r
                WHERE   masterid = 3533933

                ) q
        UNION ALL
        SELECT  *
        FROM    (
                SELECT  c.id, c.set, c.parent, r.masterid
                FROM    rows r
                JOIN    a_storage.node c
                ON      c.parent = r.id

                ) q
        )
SELECT  r.masterid, r.id AS nodeid
FROM    rows r



                                                                           QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
 CTE Scan on rows r  (cost=2742105.92..2862119.94 rows=6000701 width=16) (actual time=0.033..172111.204 rows=4 loops=1)
   CTE rows
     ->  Recursive Union  (cost=0.00..2742105.92 rows=6000701 width=28) (actual time=0.029..172111.183 rows=4 loops=1)
           ->  Index Scan using node_dataset_masterid on node_dataset r  (cost=0.00..8.60 rows=1 width=28) (actual time=0.025..0.027 rows=1 loops=1)
                 Index Cond: (masterid = 3533933)
           ->  Hash Join  (cost=0.33..262208.33 rows=600070 width=28) (actual time=40628.371..57370.361 rows=1 loops=3)
                 Hash Cond: (c.parent = r.id)
                 ->  Append  (cost=0.00..211202.04 rows=12001404 width=20) (actual time=0.011..46365.669 rows=12000004 loops=3)
                       ->  Seq Scan on node c  (cost=0.00..24.00 rows=1400 width=20) (actual time=0.002..0.002 rows=0 loops=3)
                       ->  Seq Scan on node_dataset c  (cost=0.00..55001.01 rows=3000001 width=20) (actual time=0.007..3426.593 rows=3000001 loops=3)
                       ->  Seq Scan on node_stammdaten c  (cost=0.00..52059.01 rows=3000001 width=20) (actual time=0.008..9049.189 rows=3000001 loops=3)
                       ->  Seq Scan on node_stammdaten_adresse c  (cost=0.00..52059.01 rows=3000001 width=20) (actual time=3.455..8381.725 rows=3000001 loops=3)
                       ->  Seq Scan on node_testdaten c  (cost=0.00..52059.01 rows=3000001 width=20) (actual time=1.810..5259.178 rows=3000001 loops=3)
                 ->  Hash  (cost=0.20..0.20 rows=10 width=16) (actual time=0.010..0.010 rows=1 loops=3)
                       ->  WorkTable Scan on rows r  (cost=0.00..0.20 rows=10 width=16) (actual time=0.002..0.004 rows=1 loops=3)
 Total runtime: 172111.371 ms
(16 rows)

(END)

到目前为止,规划者决定选择hash连接(好的),但不选择索引(坏的)。
在执行以下操作之后:
SET enable_hashjoins TO false;

解释的查询如下:
                                                                                    QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 CTE Scan on rows r  (cost=15198247.00..15318261.02 rows=6000701 width=16) (actual time=0.038..49.221 rows=4 loops=1)
   CTE rows
     ->  Recursive Union  (cost=0.00..15198247.00 rows=6000701 width=28) (actual time=0.032..49.201 rows=4 loops=1)
           ->  Index Scan using node_dataset_masterid on node_dataset r  (cost=0.00..8.60 rows=1 width=28) (actual time=0.028..0.031 rows=1 loops=1)
                 Index Cond: (masterid = 3533933)
           ->  Nested Loop  (cost=0.00..1507822.44 rows=600070 width=28) (actual time=10.384..16.382 rows=1 loops=3)
                 Join Filter: (r.id = c.parent)
                 ->  WorkTable Scan on rows r  (cost=0.00..0.20 rows=10 width=16) (actual time=0.001..0.003 rows=1 loops=3)
                 ->  Append  (cost=0.00..113264.67 rows=3001404 width=20) (actual time=8.546..12.268 rows=1 loops=4)
                       ->  Seq Scan on node c  (cost=0.00..24.00 rows=1400 width=20) (actual time=0.001..0.001 rows=0 loops=4)
                       ->  Bitmap Heap Scan on node_dataset c  (cost=58213.87..113214.88 rows=3000001 width=20) (actual time=1.906..1.906 rows=0 loops=4)
                             Recheck Cond: (c.parent = r.id)
                             ->  Bitmap Index Scan on node_dataset_parent  (cost=0.00..57463.87 rows=3000001 width=0) (actual time=1.903..1.903 rows=0 loops=4)
                                   Index Cond: (c.parent = r.id)
                       ->  Index Scan using node_stammdaten_parent on node_stammdaten c  (cost=0.00..8.60 rows=1 width=20) (actual time=3.272..3.273 rows=0 loops=4)
                             Index Cond: (c.parent = r.id)
                       ->  Index Scan using node_stammdaten_adresse_parent on node_stammdaten_adresse c  (cost=0.00..8.60 rows=1 width=20) (actual time=4.333..4.333 rows=0 loops=4)
                             Index Cond: (c.parent = r.id)
                       ->  Index Scan using node_testdaten_parent on node_testdaten c  (cost=0.00..8.60 rows=1 width=20) (actual time=2.745..2.746 rows=0 loops=4)
                             Index Cond: (c.parent = r.id)
 Total runtime: 49.349 ms
(21 rows)

(END)

->更快,因为索引被使用了。
注意:第二个查询的成本比第一个查询要高一些。
所以主要的问题是:为什么规划者要做第一个决定,而不是第二个?
同样有趣的是:
通过
将enable_seqscan设置为false;
我是临时工。禁用序列扫描。比规划者使用索引和散列连接,查询仍然很慢。所以问题似乎是散列连接。
也许有人能帮上忙?
泰铢,右。

最佳答案

如果您的解释与实际情况有显著差异(成本较低,但时间较长),则很可能您的统计数据已过时,或是属于非代表性样本。
用新的统计数据再试一次。如果这没有帮助,请增加样本大小并再次生成统计信息。

关于sql - 奇怪:规划者以较低的成本做出决策,但是(非常)查询运行时间长,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3063942/

10-11 04:15
查看更多