问题是,我的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倍。 我错过了什么。替代方法/查询做分页? 配置参数?