Postgresql OFFSET会导致错误的查询计划

时间:2015-06-08 11:38:00

标签: sql performance postgresql query-performance

问题是,我的postgres SQL查询表现不佳。我需要按顺序获取产品,每次大约40(LIMIT 40),一个分页。

使用此查询:

SELECT *
FROM "Product" AS p
WHERE "Category" IN ( SELECT "id"
                      FROM "Category"
                      WHERE "lft" BETWEEN 678 AND 711)
ORDER BY "id" ASC
OFFSET 0 LIMIT 1;

带来良好的查询:

Limit  (cost=0.69..14.74 rows=1 width=742) (actual time=3.573..3.575 rows=1 loops=1)
  ->  Nested Loop Semi Join  (cost=0.69..83458.11 rows=5943 width=742) (actual time=3.569..3.569 rows=1 loops=1)
        ->  Index Scan using "Product_pkey" on "Product" p  (cost=0.42..42353.33 rows=137739 width=742) (actual time=0.034..1.021 rows=233 loops=1)
        ->  Index Scan using "Category_pkey" on "Category"  (cost=0.27..0.30 rows=1 width=4) (actual time=0.007..0.007 rows=0 loops=233)
              Index Cond: (id = p."Category")
              Filter: ((lft >= 678) AND (lft <= 711))
              Rows Removed by Filter: 1
Planning time: 1.448 ms
Execution time: 3.773 ms

这另外有更多的偏移,应该是其他页面(720 /限制),非常慢。

SELECT *
FROM "Product" AS p
WHERE "Category" IN ( SELECT "id"
                      FROM "Category"
                      WHERE "lft" BETWEEN 678 AND 711 )
ORDER BY "id" ASC
OFFSET 720 LIMIT 1;

EXPLAIN ANALYZE结果:

Limit  (cost=9392.89..9405.93 rows=1 width=742) (actual time=5452.898..5452.900 rows=1 loops=1)
  ->  Nested Loop Semi Join  (cost=4.87..77495.16 rows=5943 width=742) (actual time=12.126..5452.228 rows=721 loops=1)
        Join Filter: (p."Category" = "Category".id)
        Rows Removed by Join Filter: 2322489
        ->  Index Scan using "Product_pkey" on "Product" p  (cost=0.42..42353.33 rows=137739 width=742) (actual time=0.041..316.765 rows=136977 loops=1)
        ->  Materialize  (cost=4.45..18.43 rows=17 width=4) (actual time=0.001..0.017 rows=17 loops=136977)
              ->  Bitmap Heap Scan on "Category"  (cost=4.45..18.35 rows=17 width=4) (actual time=0.060..0.137 rows=17 loops=1)
                    Recheck Cond: ((lft >= 678) AND (lft <= 711))"
                    Heap Blocks: exact=9
                    ->  Bitmap Index Scan on "Category_lft_idx"  (cost=0.00..4.44 rows=17 width=0) (actual time=0.040..0.040 rows=17 loops=1)
                          Index Cond: ((lft >= 678) AND (lft <= 711))
Planning time: 1.491 ms
Execution time: 5453.115 ms

禁用nestloop查询计划在某些情况下可能会有所帮助,但不会太多。

SET enable_nestloop = off;

EXPLAIN ANALYZE结果:

Limit  (cost=12249.25..12249.26 rows=1 width=742) (actual time=342.047..342.048 rows=1 loops=1)
  ->  Sort  (cost=12247.45..12262.31 rows=5943 width=742) (actual time=340.666..341.388 rows=721 loops=1)
        Sort Key: p.id"
        Sort Method: quicksort  Memory: 634kB
        ->  Hash Semi Join  (cost=18.56..11935.63 rows=5943 width=742) (actual time=1.736..337.872 rows=729 loops=1)
              Hash Cond: (p."Category" = "Category".id)
              ->  Seq Scan on "Product" p  (cost=0.00..11489.39 rows=137739 width=742) (actual time=0.005..148.299 rows=137739 loops=1)
              ->  Hash  (cost=18.35..18.35 rows=17 width=4) (actual time=0.120..0.120 rows=17 loops=1)
                    Buckets: 1024  Batches: 1  Memory Usage: 1kB
                    ->  Bitmap Heap Scan on "Category"  (cost=4.45..18.35 rows=17 width=4) (actual time=0.032..0.095 rows=17 loops=1)
                          Recheck Cond: ((lft >= 678) AND (lft <= 711))
                          Heap Blocks: exact=9
                          ->  Bitmap Index Scan on "Category_lft_idx"  (cost=0.00..4.44 rows=17 width=0) (actual time=0.021..0.021 rows=17 loops=1)
                                Index Cond: ((lft >= 678) AND (lft <= 711))
Planning time: 0.857 ms
Execution time: 342.182 ms

加入:

SELECT *
FROM "Product" AS p
    INNER JOIN "Category" ON ("Category".id = p."Category")
WHERE "lft" BETWEEN 678 AND 711
ORDER BY p."id" ASC
OFFSET 720 LIMIT 1;

EXPLAIN ANALYZE:

Limit  (cost=9916.58..9930.34 rows=1 width=1026) (actual time=5474.380..5474.382 rows=1 loops=1)
  ->  Nested Loop  (cost=4.87..77495.16 rows=5629 width=1026) (actual time=11.473..5473.686 rows=721 loops=1)
        Join Filter: (p."Category" = "Category".id)
        Rows Removed by Join Filter: 2327885
        ->  Index Scan using "Product_pkey" on "Product" p  (cost=0.42..42353.33 rows=137739 width=742) (actual time=0.020..309.544 rows=136977 loops=1)
        ->  Materialize  (cost=4.45..18.43 rows=17 width=284) (actual time=0.001..0.017 rows=17 loops=136977)
              ->  Bitmap Heap Scan on "Category"  (cost=4.45..18.35 rows=17 width=284) (actual time=0.029..0.060 rows=17 loops=1)
                    Recheck Cond: ((lft >= 678) AND (lft <= 711))
                    Heap Blocks: exact=9
                    ->  Bitmap Index Scan on "Category_lft_idx" (cost=0.00..4.44 rows=17 width=0) (actual time=0.020..0.020 rows=17 loops=1)
                          Index Cond: ((lft >= 678) AND (lft <= 711))
Planning time: 0.811 ms
Execution time: 5474.545 ms

SET enable_bitmapscan = off;
SET enable_hashagg = off;
SET enable_hashjoin = off;
SET enable_indexscan = off;
SET enable_indexonlyscan = off;
SET enable_material = off;
SET enable_mergejoin = off;
SET enable_nestloop = off;
SET enable_seqscan = off;
SET enable_sort = off;
SET enable_tidscan = off;


/* Enabling only one */
    SET enable_bitmapscan = on; Time: 25 ms
    SET enable_hashagg = on; Time: 3753 ms
    SET enable_hashjoin = on; Time: 270 ms
    SET enable_indexscan = on; Time: 715 ms
    SET enable_indexonlyscan = on; Time: 3659 ms
    SET enable_material = on; Time: 750 ms
    SET enable_mergejoin = on; Time: 218 ms
    SET enable_nestloop = on; Time: 3637 ms
    SET enable_seqscan = on; Time: 1251 ms
    SET enable_sort = on; Time: 3635 ms
    SET enable_tidscan = on; time: 3650

在某些情况下,默认选择的计划程序比最佳计划程序贵200倍。 我错过了什么。替代方法/查询做分页? 配置参数?

0 个答案:

没有答案