1、DISTINCT查询的增量排序
-- SetupCREATE TABLE distinct_test (a INT, b INT);INSERT INTO distinct_testSELECT x,1 FROM generate_series(1,1000000)x;CREATE INDEX on distinct_test(a);VACUUM ANALYZE distinct_test;EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)SELECT DISTINCT a,b FROM distinct_test;
QUERY PLAN---------------------------------------------------------------HashAggregate (actual rows=1000000 loops=1)Group Key: a, bBatches: 81 Memory Usage: 11153kB Disk Usage: 31288kB-> Seq Scan on distinct_test (actual rows=1000000 loops=1)Planning Time: 0.065 msExecution Time: 414.226 ms(6 rows)
QUERY PLAN------------------------------------------------------------------Unique (actual rows=1000000 loops=1)-> Incremental Sort (actual rows=1000000 loops=1)Sort Key: a, bPresorted Key: aFull-sort Groups: 31250 Sort Method: quicksort Average Memory: 26kB Peak Memory: 26kB-> Index Scan using distinct_test_a_idx on distinct_test (actual rows=1000000 loops=1)Planning Time: 0.108 msExecution Time: 263.167 ms(8 rows)
2、更快的 ORDER BY/DISTINCT聚合
-- SetupCREATE TABLE aggtest (a INT, b text);INSERT INTO aggtest SELECT a,md5((b%100)::text) FROM generate_series(1,10) a, generate_series(1,100000)b;CREATE INDEX ON aggtest(a,b);VACUUM FREEZE ANALYZE aggtest;EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF, BUFFERS)SELECT a,COUNT(DISTINCT b) FROM aggtest GROUP BY a;
QUERY PLAN---------------------------------------------------------------GroupAggregate (actual rows=10 loops=1)Group Key: aBuffers: shared hit=892, temp read=4540 written=4560-> Index Only Scan using aggtest_a_b_idx on aggtest (actual rows=1000000 loops=1)Heap Fetches: 0Buffers: shared hit=892Planning Time: 0.122 msExecution Time: 302.693 ms(8 rows)
QUERY PLAN---------------------------------------------------------------GroupAggregate (actual rows=10 loops=1)Group Key: aBuffers: shared hit=892-> Index Only Scan using aggtest_a_b_idx on aggtest (actual rows=1000000 loops=1)Heap Fetches: 0Buffers: shared hit=892Planning Time: 0.061 msExecution Time: 115.534 ms(8 rows)
3、UNION ALL查询的Memoize算子
-- SetupCREATE TABLE t1 (a INT PRIMARY KEY);CREATE TABLE t2 (a INT PRIMARY KEY);CREATE TABLE lookup (a INT);INSERT INTO t1 SELECT x FROM generate_Series(1,10000) x;INSERT INTO t2 SELECT x FROM generate_Series(1,10000) x;INSERT INTO lookup SELECT x%10+1 FROM generate_Series(1,1000000)x;ANALYZE t1,t2,lookup;EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)SELECT * FROM (SELECT * FROM t1 UNION ALL SELECT * FROM t2) tINNER JOIN lookup l ON l.a = t.a;
QUERY PLAN-------------------------------------------------------------------------------Nested Loop (actual rows=2000000 loops=1)-> Seq Scan on lookup l (actual rows=1000000 loops=1)-> Append (actual rows=2 loops=1000000)-> Index Only Scan using t1_pkey on t1 (actual rows=1 loops=1000000)Index Cond: (a = l.a)Heap Fetches: 1000000-> Index Only Scan using t2_pkey on t2 (actual rows=1 loops=1000000)Index Cond: (a = l.a)Heap Fetches: 1000000Planning Time: 0.223 msExecution Time: 1926.151 ms(11 rows)
QUERY PLAN---------------------------------------------------------------------------------Nested Loop (actual rows=2000000 loops=1)-> Seq Scan on lookup l (actual rows=1000000 loops=1)-> Memoize (actual rows=2 loops=1000000)Cache Key: l.aCache Mode: logicalHits: 999990 Misses: 10 Evictions: 0 Overflows: 0 Memory Usage: 2kB-> Append (actual rows=2 loops=10)-> Index Only Scan using t1_pkey on t1 (actual rows=1 loops=10)Index Cond: (a = l.a)Heap Fetches: 10-> Index Only Scan using t2_pkey on t2 (actual rows=1 loops=10)Index Cond: (a = l.a)Heap Fetches: 10Planning Time: 0.229 msExecution Time: 282.120 ms(15 rows)
4、支持Right Anti Join
-- SetupCREATE TABLE small(a int);CREATE TABLE large(a int);INSERT INTO smallSELECT a FROM generate_series(1,100) a;INSERT INTO largeSELECT a FROM generate_series(1,1000000) a;VACUUM ANALYZE small,large;EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)SELECT * FROM small sWHERE NOT EXISTS(SELECT 1 FROM large l WHERE s.a = l.a);
QUERY PLAN---------------------------------------------------------------Hash Anti Join (actual rows=0 loops=1)Hash Cond: (s.a = l.a)-> Seq Scan on small s (actual rows=100 loops=1)-> Hash (actual rows=1000000 loops=1)Buckets: 262144 Batches: 8 Memory Usage: 6446kB-> Seq Scan on large l (actual rows=1000000 loops=1)Planning Time: 0.103 msExecution Time: 139.023 ms(8 rows)
QUERY PLAN-----------------------------------------------------------Hash Right Anti Join (actual rows=0 loops=1)Hash Cond: (l.a = s.a)-> Seq Scan on large l (actual rows=1000000 loops=1)-> Hash (actual rows=100 loops=1)Buckets: 1024 Batches: 1 Memory Usage: 12kB-> Seq Scan on small s (actual rows=100 loops=1)Planning Time: 0.094 msExecution Time: 77.076 ms(8 rows)
5、并行Hash Full和Right Joins
-- SetupCREATE TABLE odd (a INT);CREATE TABLE even (a INT);INSERT INTO oddSELECT a FROM generate_series(1,1000000,2) a;INSERT INTO evenSELECT a FROM generate_series(2,1000000,2) a;VACUUM ANALYZE odd, even;EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)SELECT COUNT(o.a),COUNT(e.a) FROM odd o FULL JOIN even e ON o.a = e.a;
QUERY PLAN-------------------------------------------------------------------Aggregate (actual rows=1 loops=1)-> Hash Full Join (actual rows=1000000 loops=1)Hash Cond: (o.a = e.a)-> Seq Scan on odd o (actual rows=500000 loops=1)-> Hash (actual rows=500000 loops=1)Buckets: 262144 Batches: 4 Memory Usage: 6439kB-> Seq Scan on even e (actual rows=500000 loops=1)Planning Time: 0.079 msExecution Time: 220.677 ms(9 rows)
QUERY PLAN--------------------------------------------------------------------------------Finalize Aggregate (actual rows=1 loops=1)-> Gather (actual rows=2 loops=1)Workers Planned: 1Workers Launched: 1-> Partial Aggregate (actual rows=1 loops=2)-> Parallel Hash Full Join (actual rows=500000 loops=2)Hash Cond: (o.a = e.a)-> Parallel Seq Scan on odd o (actual rows=250000 loops=2)-> Parallel Hash (actual rows=250000 loops=2)Buckets: 262144 Batches: 4 Memory Usage: 6976kB-> Parallel Seq Scan on even e (actual rows=250000 loops=2)Planning Time: 0.161 msExecution Time: 129.769 ms(13 rows)
6、优化窗口函数frame子句
-- SetupCREATE TABLE scores (id INT PRIMARY KEY, score INT);INSERT INTO scores SELECT s,random()*10 FROM generate_series(1,1000000)s;CREATE INDEX ON scores(score);VACUUM ANALYZE scores;EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)SELECT * FROM (SELECT id,ROW_NUMBER() OVER (ORDER BY score) rn,scoreFROM scores) m WHERE rn <= 10;
QUERY PLAN-------------------------------------------------------------------------------WindowAgg (actual rows=10 loops=1)Run Condition: (row_number() OVER (?) <= 10)-> Index Scan using scores_score_idx on scores (actual rows=50410 loops=1)Planning Time: 0.096 msExecution Time: 29.775 ms(5 rows)
QUERY PLAN----------------------------------------------------------------------------WindowAgg (actual rows=10 loops=1)Run Condition: (row_number() OVER (?) <= 10)-> Index Scan using scores_score_idx on scores (actual rows=11 loops=1)Planning Time: 0.191 msExecution Time: 0.058 ms(5 rows)
7、优化各种窗口函数
-- SetupCREATE TABLE marathon (id INT PRIMARY KEY, time INTERVAL NOT NULL);INSERT INTO marathonSELECT id,'03:00:00'::interval + (CAST(RANDOM() * 3600 AS INT) || 'secs')::INTERVAL - (CAST(RANDOM() * 3600 AS INT) || ' secs')::INTERVALFROM generate_series(1,50000) id;CREATE INDEX ON marathon (time);VACUUM ANALYZE marathon;EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)SELECT * FROM (SELECT *,percent_rank() OVER (ORDER BY time) prFROM marathon) m WHERE pr <= 0.01;
QUERY PLAN-----------------------------------------------------------------------Subquery Scan on m (actual rows=500 loops=1)Filter: (m.pr <= '0.01'::double precision)Rows Removed by Filter: 49500-> WindowAgg (actual rows=50000 loops=1)-> Index Scan using marathon_time_idx on marathon (actual rows=50000 loops=1)Planning Time: 0.108 msExecution Time: 84.358 ms(7 rows)
QUERY PLAN-----------------------------------------------------------------------WindowAgg (actual rows=500 loops=1)Run Condition: (percent_rank() OVER (?) <= '0.01'::double precision)-> Index Scan using marathon_time_idx on marathon (actual rows=50000 loops=1)Planning Time: 0.180 msExecution Time: 19.454 ms(5 rows)
8、分区表的join消除
-- SetupCREATE TABLE part_tab (id BIGINT PRIMARY KEY, payload TEXT) PARTITION BY HASH(id);CREATE TABLE part_tab_p0 PARTITION OF part_tab FOR VALUES WITH (modulus 2, remainder 0);CREATE TABLE part_tab_p1 PARTITION OF part_tab FOR VALUES WITH (modulus 2, remainder 1);CREATE TABLE normal_table (id INT, part_tab_id BIGINT);EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)SELECT nt.* FROM normal_table nt LEFT JOIN part_tab pt ON nt.part_tab_id = pt.id;
QUERY PLAN-------------------------------------------------------------------Merge Right Join (actual rows=0 loops=1)Merge Cond: (pt.id = nt.part_tab_id)-> Merge Append (actual rows=0 loops=1)Sort Key: pt.id-> Index Only Scan using part_tab_p0_pkey on part_tab_p0 pt_1 (actual rows=0 loops=1)Heap Fetches: 0-> Index Only Scan using part_tab_p1_pkey on part_tab_p1 pt_2 (actual rows=0 loops=1)Heap Fetches: 0-> Sort (actual rows=0 loops=1)Sort Key: nt.part_tab_idSort Method: quicksort Memory: 25kB-> Seq Scan on normal_table nt (actual rows=0 loops=1)Planning Time: 0.325 msExecution Time: 0.037 ms(14 rows)
QUERY PLAN-----------------------------------------------------Seq Scan on normal_table nt (actual rows=0 loops=1)Planning Time: 0.244 msExecution Time: 0.015 ms(3 rows)
9、DISTINCT查询
-- SetupCREATE TABLE abc (a int, b int, c int);INSERT INTO abc SELECT a%10,a%10,a%10 FROM generate_series(1,1000000)a;VACUUM ANALYZE abc;EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)SELECT DISTINCT a,b,c FROM abc WHERE a = 5 AND b = 5 AND c = 5;
QUERY PLAN------------------------------------------------------------------------Unique (actual rows=1 loops=1)-> Gather (actual rows=3 loops=1)Workers Planned: 2Workers Launched: 2-> Unique (actual rows=1 loops=3)-> Parallel Seq Scan on abc (actual rows=33333 loops=3)Filter: ((a = 5) AND (b = 5) AND (c = 5))Rows Removed by Filter: 300000Planning Time: 0.114 msExecution Time: 30.381 ms(10 rows)
QUERY PLAN---------------------------------------------------Limit (actual rows=1 loops=1)-> Seq Scan on abc (actual rows=1 loops=1)Filter: ((a = 5) AND (b = 5) AND (c = 5))Rows Removed by Filter: 4Planning Time: 0.109 msExecution Time: 0.025 ms(6 rows)
10、MergeJoin后增量排序
-- SetupCREATE TABLE a (a INT, b INT);CREATE TABLE b (x INT, y INT);INSERT INTO a SELECT a,a FROM generate_series(1,1000000) a;INSERT INTO b SELECT a,a FROM generate_series(1,1000000) a;VACUUM ANALYZE a, b;SET enable_hashjoin=0;SET max_parallel_workers_per_gather=0;EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)SELECT a,b,count(*) FROM a INNER JOIN b ON a.a = b.x GROUP BY a,b ORDER BY a DESC, b;
QUERY PLAN---------------------------------------------------------------------------GroupAggregate (actual rows=1000000 loops=1)Group Key: a.a, a.b-> Sort (actual rows=1000000 loops=1)Sort Key: a.a DESC, a.bSort Method: external merge Disk: 17664kB-> Merge Join (actual rows=1000000 loops=1)Merge Cond: (a.a = b.x)-> Sort (actual rows=1000000 loops=1)Sort Key: a.aSort Method: external merge Disk: 17664kB-> Seq Scan on a (actual rows=1000000 loops=1)-> Materialize (actual rows=1000000 loops=1)-> Sort (actual rows=1000000 loops=1)Sort Key: b.xSort Method: external merge Disk: 11768kB-> Seq Scan on b (actual rows=1000000 loops=1)Planning Time: 0.175 msExecution Time: 1010.738 ms(18 rows)
QUERY PLAN---------------------------------------------------------------------------GroupAggregate (actual rows=1000000 loops=1)Group Key: a.a, a.b-> Incremental Sort (actual rows=1000000 loops=1)Sort Key: a.a DESC, a.bPresorted Key: a.aFull-sort Groups: 31250 Sort Method: quicksort Average Memory: 26kB Peak Memory: 26kB-> Merge Join (actual rows=1000000 loops=1)Merge Cond: (a.a = b.x)-> Sort (actual rows=1000000 loops=1)Sort Key: a.a DESCSort Method: external merge Disk: 17672kB-> Seq Scan on a (actual rows=1000000 loops=1)-> Materialize (actual rows=1000000 loops=1)-> Sort (actual rows=1000000 loops=1)Sort Key: b.x DESCSort Method: external merge Disk: 11768kB-> Seq Scan on b (actual rows=1000000 loops=1)Planning Time: 0.140 msExecution Time: 915.589 ms(19 rows)
原文
文章转载自yanzongshuaiDBA,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




