Hello, Thanks for the feedback so far! Continue with the previous report, we sharing another four interesting cases that SQLFuzz discovered. (previous discussion: https://www.postgresql.org/message-id/flat/BN6PR07MB3409EE6CAAF8CCF43820AFB9EE670%40BN6PR07MB3409.namprd07.prod.outlook.com#acc68f0fbd8f0b207e162d2dd401d3e8 )
Here’s the time taken to execute four SQL queries on old (v9.5.16) and newer version (v11.2) of PostgreSQL (in milliseconds): +----------------------+--------+---------+---------+---------+ | | scale1 | scale10 | scale50 | scale300| +----------------------+--------+---------+---------+---------+ | Case-5 (v9.5.16) | 39 | 183 | 1459 | 11125 | | Case-5 (v11.2) | 73 | 620 | 4818 | 16956 | +----------------------+--------+---------+---------+---------+ | Case-6 (v9.5.16) | 46 | 329 | 15096 | 10721 | | Case-6 (v11.2) | 81 | 671 | 64808 | 26919 | +----------------------+--------+---------+---------+---------+ | Case-7 (v9.5.16) | 19 | X | X | X | | Case-7 (v11.2) | 46 | X | X | X | +----------------------+--------+---------+---------+---------+ | Case-8 (v9.5.16) | 215 | 2108 | 10460 | 64959 | | Case-8 (v11.2) | 449 | 3997 | 20246 | 130595 | +----------------------+--------+---------+---------+---------+ For each regression, we share: 1) the associated query, 2) the commit that activated it, 3) our high-level analysis, and 4) query execution plans in old and new versions of PostgreSQL. All these regressions are observed on the latest version. (v11.2 and v9.5.16) * You can download the queries at: https://gts3.org/~/jjung/tpcc/case2.tar.gz * You can reproduce the result by using the same setup that we described before: https://www.postgresql.org/message-id/BN6PR07MB3409922471073F2B619A8CA4EE640%40BN6PR07MB3409.namprd07.prod.outlook.com - As Andrew mentioned before, we increased default work_mem to 128MB Best regards, Jinho Jung #### QUERY 5 EXPLAIN ANALYZE select ref_0.c_zip as c0 from public.customer as ref_0 where EXISTS ( select ref_1.ol_d_id as c10 from public.order_line as ref_1 where (ref_1.ol_o_id <> ref_0.c_d_id) ) - Commit : 7ca25b7 - Our analysis: We believe newer version is slow when the number of rows in the filter is small. - Query execution plans: [Old version] Nested Loop Semi Join (cost=0.00..15317063263550.52 rows=1 width=10) (actual time=0.019..10888.266 rows=9000000 loops=1) Join Filter: (ref_1.ol_o_id <> ref_0.c_d_id) Rows Removed by Join Filter: 11700000 -> Seq Scan on customer ref_0 (cost=0.00..770327.00 rows=9000000 width=14) (actual time=0.008..7541.944 rows=9000000 loops=1) -> Materialize (cost=0.00..2813223.52 rows=90017568 width=4) (actual time=0.000..0.000 rows=2 loops=9000000) -> Seq Scan on order_line ref_1 (cost=0.00..2011503.68 rows=90017568 width=4) (actual time=0.005..0.007 rows=14 loops=1) Planning time: 0.401 ms Execution time: 11125.538 ms [New version] Nested Loop Semi Join (cost=0.00..3409260.89 rows=9000000 width=10) (actual time=0.033..16732.988 rows=9000000 loops=1) Join Filter: (ref_1.ol_o_id <> ref_0.c_d_id) Rows Removed by Join Filter: 11700000 -> Seq Scan on customer ref_0 (cost=0.00..770327.00 rows=9000000 width=14) (actual time=0.017..2113.336 rows=9000000 loops=1) -> Seq Scan on order_line ref_1 (cost=0.00..2011503.68 rows=90017568 width=4) (actual time=0.001..0.001 rows=2 loops=9000000) Planning Time: 0.615 ms Execution Time: 16956.115 ms ##### QUERY 6 select distinct ref_0.h_data as c0, ref_0.h_c_id as c1 from public.history as ref_0 left join public.item as ref_1 on (ref_1.i_im_id < -1) where ref_1.i_price is NULL - Our analysis: We think that the 'merge sort' makes slow execution. We are wondering why newer version applies external merge sort in this case. - Commit: 3fc6e2d (big patch) - Query execution plans: [Old version] HashAggregate (cost=1312274.26..1312274.27 rows=1 width=21) (actual time=7288.727..10443.586 rows=9000000 loops=1) Group Key: ref_0.h_data, ref_0.h_c_id -> Nested Loop Left Join (cost=0.00..1312274.26 rows=1 width=21) (actual time=26.965..2463.231 rows=9000000 loops=1) Filter: (ref_1.i_price IS NULL) -> Seq Scan on history ref_0 (cost=0.00..184795.61 rows=8999661 width=21) (actual time=0.347..795.936 rows=9000000 loops=1) -> Materialize (cost=0.00..2521.05 rows=10 width=6) (actual time=0.000..0.000 rows=0 loops=9000000) -> Seq Scan on item ref_1 (cost=0.00..2521.00 rows=10 width=6) (actual time=26.610..26.610 rows=0 loops=1) Filter: (i_im_id < '-1'::integer) Rows Removed by Filter: 100000 Planning time: 1.538 ms Execution time: 10721.259 ms [New version] Unique (cost=1312334.34..1312334.35 rows=1 width=21) (actual time=21444.459..26651.868 rows=9000000 loops=1) -> Sort (cost=1312334.34..1312334.35 rows=1 width=21) (actual time=21444.457..25629.389 rows=9000000 loops=1) Sort Key: ref_0.h_data, ref_0.h_c_id Sort Method: external merge Disk: 285384kB -> Nested Loop Left Join (cost=0.00..1312334.33 rows=1 width=21) (actual time=21.328..2409.302 rows=9000000 loops=1) Filter: (ref_1.i_price IS NULL) -> Seq Scan on history ref_0 (cost=0.00..184800.06 rows=9000106 width=21) (actual time=0.320..734.376 rows=9000000 loops=1) -> Materialize (cost=0.00..2521.05 rows=10 width=6) (actual time=0.000..0.000 rows=0 loops=9000000) -> Seq Scan on item ref_1 (cost=0.00..2521.00 rows=10 width=6) (actual time=21.000..21.001 rows=0 loops=1) Filter: (i_im_id < '-1'::integer) Rows Removed by Filter: 100000 Planning Time: 1.426 ms Execution Time: 26919.635 ms ##### QUERY 7 select ref_0.c_id as c0 from public.customer as ref_0 where EXISTS ( select ref_0.c_city as c0 from public.order_line as ref_1 left join public.new_order as ref_2 on (ref_1.ol_supply_w_id = ref_2.no_w_id) where (ref_1.ol_delivery_d > ref_0.c_since) ) - Our analysis : Parallel execution seems a problem. We also want to ask whether only one worker is intended behavior of Postgres because we think parallel execution with less than two workers is not parallel. - Another interesting finding: this query cannot be finished within one day if we incrase the size of DB (e.g., from scale factor 1 to scale factor 10/50/300). - Commit: 16be2fd - Query execution plans: [Old version] Nested Loop Semi Join (cost=224.43..910152608046.08 rows=10000 width=4) (actual time=2.619..18.042 rows=30000 loops=1) Join Filter: (ref_1.ol_delivery_d > ref_0.c_since) -> Seq Scan on customer ref_0 (cost=0.00..2569.00 rows=30000 width=12) (actual time=0.003..4.530 rows=30000 loops=1) -> Materialize (cost=224.43..48521498.97 rows=2406886812 width=8) (actual time=0.000..0.000 rows=1 loops=30000) -> Hash Left Join (cost=224.43..27085162.91 rows=2406886812 width=8) (actual time=2.612..2.612 rows=1 loops=1) Hash Cond: (ref_1.ol_supply_w_id = ref_2.no_w_id) -> Seq Scan on order_line ref_1 (cost=0.00..6711.48 rows=300148 width=12) (actual time=0.002..0.002 rows=1 loops=1) -> Hash (cost=124.19..124.19 rows=8019 width=4) (actual time=2.571..2.571 rows=8019 loops=1) Buckets: 8192 Batches: 1 Memory Usage: 346kB -> Seq Scan on new_order ref_2 (cost=0.00..124.19 rows=8019 width=4) (actual time=0.174..1.539 rows=8019 loops=1) Planning time: 0.605 ms Execution time: 19.045 ms [New version] Gather (cost=1224.43..672617098015.10 rows=10000 width=4) (actual time=3.099..45.077 rows=30000 loops=1) Workers Planned: 1 Workers Launched: 1 -> Nested Loop Semi Join (cost=224.43..672617096015.10 rows=5882 width=4) (actual time=2.307..38.258 rows=15000 loops=2) Join Filter: (ref_1.ol_delivery_d > ref_0.c_since) -> Parallel Seq Scan on customer ref_0 (cost=0.00..2445.47 rows=17647 width=12) (actual time=0.003..2.668 rows=15000 loops=2) -> Hash Left Join (cost=224.43..27085162.91 rows=2406886812 width=8) (actual time=0.002..0.002 rows=1 loops=30000) Hash Cond: (ref_1.ol_supply_w_id = ref_2.no_w_id) -> Seq Scan on order_line ref_1 (cost=0.00..6711.48 rows=300148 width=12) (actual time=0.001..0.001 rows=1 loops=30000) -> Hash (cost=124.19..124.19 rows=8019 width=4) (actual time=2.211..2.211 rows=8019 loops=2) Buckets: 8192 Batches: 1 Memory Usage: 346kB -> Seq Scan on new_order ref_2 (cost=0.00..124.19 rows=8019 width=4) (actual time=0.086..1.179 rows=8019 loops=2) Planning Time: 0.611 ms Execution Time: 46.195 ms ##### QUERY 8 select ref_0.ol_d_id as c0 from public.order_line as ref_0 left join ( select ref_1.ol_supply_w_id as c0, ref_1.ol_d_id as c2 from public.order_line as ref_1 where ref_1.ol_o_id < 1 ) as subq_0 on (subq_0.c2 = ref_0.ol_o_id) where EXISTS ( select ref_2.o_ol_cnt as c0 from public.oorder as ref_2 where nullif(ref_2.o_d_id, subq_0.c0) is not NULL ); - Commit: 0c2070c - Our analysis : We are not sure about the root cause of this regression. This might have to do with parallel execution. - Query execution plans: [Old version] Nested Loop Semi Join (cost=3488355.85..210034755085.67 rows=245615461 width=4) (actual time=32830.372..62745.966 rows=90017507 loops=1) Join Filter: (NULLIF(ref_2.o_d_id, ref_1.ol_supply_w_id) IS NOT NULL) -> Hash Right Join (cost=3488355.85..9115461.16 rows=246849710 width=8) (actual time=32829.980..48232.002 rows=90017507 loops=1) Hash Cond: (ref_1.ol_d_id = ref_0.ol_o_id) -> Index Scan using order_line_pkey on order_line ref_1 (cost=0.57..2076988.89 rows=8461 width=8) (actual time=5346.547..5346.547 rows=0 loops=1) Index Cond: (ol_o_id < 1) -> Hash (cost=2011503.68..2011503.68 rows=90017568 width=8) (actual time=27466.438..27466.438 rows=90017507 loops=1) Buckets: 4194304 Batches: 64 Memory Usage: 80798kB -> Seq Scan on order_line ref_0 (cost=0.00..2011503.68 rows=90017568 width=8) (actual time=0.006..16821.719 rows=90017507 loops=1) -> Materialize (cost=0.00..245157.00 rows=9000000 width=4) (actual time=0.000..0.000 rows=1 loops=90017507) -> Seq Scan on oorder ref_2 (cost=0.00..165000.00 rows=9000000 width=4) (actual time=0.377..0.377 rows=1 loops=1) Planning time: 3.933 ms Execution time: 64959.231 ms [New version] Gather (cost=8797140.37..153823591859.11 rows=264667229 width=4) (actual time=27917.270..128050.059 rows=90017507 loops=1) Workers Planned: 2 Workers Launched: 2 -> Nested Loop Semi Join (cost=8796140.37..153797124136.21 rows=110278012 width=4) (actual time=27911.016..109588.362 rows=30005836 loops=3) Join Filter: (NULLIF(ref_2.o_d_id, ref_1.ol_supply_w_id) IS NOT NULL) -> Merge Left Join (cost=8796140.37..10646159.56 rows=110832173 width=8) (actual time=27910.620..33777.444 rows=30005836 loops=3) Merge Cond: (ref_0.ol_o_id = ref_1.ol_d_id) -> Sort (cost=6717742.99..6811511.29 rows=37507320 width=8) (actual time=22427.383..25862.373 rows=30005836 loops=3) Sort Key: ref_0.ol_o_id Sort Method: external merge Disk: 534352kB Worker 0: Sort Method: external merge Disk: 509888kB Worker 1: Sort Method: external merge Disk: 541512kB -> Parallel Seq Scan on order_line ref_0 (cost=0.00..1486401.20 rows=37507320 width=8) (actual time=0.025..14349.178 rows=30005836 loops=3) -> Sort (cost=2078397.38..2078419.66 rows=8912 width=8) (actual time=5483.221..5483.221 rows=0 loops=3) Sort Key: ref_1.ol_d_id Sort Method: quicksort Memory: 25kB Worker 0: Sort Method: quicksort Memory: 25kB Worker 1: Sort Method: quicksort Memory: 25kB -> Index Scan using order_line_pkey on order_line ref_1 (cost=0.57..2077812.68 rows=8912 width=8) (actual time=5483.203..5483.203 rows=0 loops=3) Index Cond: (ol_o_id < 1) -> Seq Scan on oorder ref_2 (cost=0.00..165000.00 rows=9000000 width=4) (actual time=0.002..0.002 rows=1 loops=90017507) Planning Time: 3.952 ms Execution Time: 130595.467 ms =================================== Following up with previous question =================================== on-going discussion: https://www.postgresql.org/message-id/flat/BN6PR07MB3409EE6CAAF8CCF43820AFB9EE670%40BN6PR07MB3409.namprd07.prod.outlook.com#acc68f0fbd8f0b207e162d2dd401d3e8 Hello Andres, Could you please share your thoughts on QUERY 3? The performance impact of this regression increases *linearly* on larger databases. We concur with Andrew in that this is related to the lack of a Materialize node and mis-costing of the Nested Loop Anti-Join. We found more than 20 regressions related to this commit. We have shared two illustrative examples (QUERIES 3A and 3B) below. - Commit: 77cd477 (Enable parallel query by default.) - Summary: Execution Time (milliseconds) When we increased the scale-factor of TPC-C to 300 (~30 GB), this query ran three times slower on v11 (24 seconds) in comparison to v9.5 (7 seconds). We also found more than 15 regressions related to the same commit and share a couple of them below. +-----------------------+--------+---------+---------+-----------+ | | scale1 | scale10 | scale50 | scale 300 | +-----------------------+--------+---------+---------+-----------+ | Query 3 (v9.5) | 28 | 248 | 1231 | 7265 | | Query 3 (v11) | 74 | 677 | 3345 | 24581 | +-----------------------+--------+---------+---------+-----------+ | Query 3A (v9.5) | 88 | 937 | 4721 | 27241 | | Query 3A (v11) | 288 | 2822 | 13838 | 85081 | +-----------------------+--------+---------+---------+-----------+ | Query 3B (v9.5) | 101 | 934 | 4824 | 29363 | | Query 3B (v11) | 200 | 2331 | 12327 | 74110 | +-----------------------+--------+---------+---------+-----------+ ###### QUERY 3: select cast(ref_1.ol_i_id as int4) as c0 from public.stock as ref_0 left join public.order_line as ref_1 on (ref_1.ol_number is not null) where ref_1.ol_number is null ###### QUERY 3A: select ref_0.ol_delivery_d as c1 from public.order_line as ref_0 where EXISTS ( select ref_1.i_im_id as c0 from public.item as ref_1 where ref_0.ol_d_id <= ref_1.i_im_id ) Execution plan: [OLD version] Nested Loop Semi Join (cost=0.00..90020417940.08 rows=30005835 width=8) (actual time=0.034..24981.895 rows=90017507 loops=1) Join Filter: (ref_0.ol_d_id <= ref_1.i_im_id) -> Seq Scan on order_line ref_0 (cost=0.00..2011503.04 rows=90017504 width=12) (actual time=0.022..7145.811 rows=90017507 loops=1) -> Materialize (cost=0.00..2771.00 rows=100000 width=4) (actual time=0.000..0.000 rows=1 loops=90017507) -> Seq Scan on item ref_1 (cost=0.00..2271.00 rows=100000 width=4) (actual time=0.006..0.006 rows=1 loops=1) Planning time: 0.290 ms Execution time: 27241.239 ms [NEW version] Gather (cost=1000.00..88047487498.82 rows=30005835 width=8) (actual time=0.265..82355.289 rows=90017507 loops=1) Workers Planned: 2 Workers Launched: 2 -> Nested Loop Semi Join (cost=0.00..88044485915.32 rows=12502431 width=8) (actual time=0.033..68529.259 rows=30005836 loops=3) Join Filter: (ref_0.ol_d_id <= ref_1.i_im_id) -> Parallel Seq Scan on order_line ref_0 (cost=0.00..1486400.93 rows=37507293 width=12) (actual time=0.023..2789.901 rows=30005836 loops=3) -> Seq Scan on item ref_1 (cost=0.00..2271.00 rows=100000 width=4) (actual time=0.001..0.001 rows=1 loops=90017507) Planning Time: 0.319 ms Execution Time: 85081.158 ms ###### QUERY 3B: select ref_0.ol_i_id as c0 from public.order_line as ref_0 where EXISTS ( select ref_0.ol_delivery_d as c0 from public.order_line as ref_1 where ref_1.ol_d_id <= cast(nullif(ref_1.ol_o_id, ref_0.ol_i_id) as int4)) Execution plan: [OLD version] Nested Loop Semi Join (cost=0.00..115638730740936.53 rows=30005835 width=4) (actual time=0.017..27009.302 rows=90017507 loops=1) Join Filter: (ref_1.ol_d_id <= NULLIF(ref_1.ol_o_id, ref_0.ol_i_id)) Rows Removed by Join Filter: 11557 -> Seq Scan on order_line ref_0 (cost=0.00..2011503.04 rows=90017504 width=4) (actual time=0.009..7199.540 rows=90017507 loops=1) -> Materialize (cost=0.00..2813221.56 rows=90017504 width=8) (actual time=0.000..0.000 rows=1 loops=90017507) -> Seq Scan on order_line ref_1 (cost=0.00..2011503.04 rows=90017504 width=8) (actual time=0.001..0.002 rows=14 loops=1) Planning time: 0.252 ms Execution time: 29363.737 ms [NEW version] Gather (cost=1000.00..84060490326155.39 rows=30005835 width=4) (actual time=0.272..71712.491 rows=90017507 loops=1) Workers Planned: 2 Workers Launched: 2 -> Nested Loop Semi Join (cost=0.00..84060487324571.89 rows=12502431 width=4) (actual time=0.046..60153.472 rows=30005836 loops=3) Join Filter: (ref_1.ol_d_id <= NULLIF(ref_1.ol_o_id, ref_0.ol_i_id)) Rows Removed by Join Filter: 1717 -> Parallel Seq Scan on order_line ref_0 (cost=0.00..1486400.93 rows=37507293 width=4) (actual time=0.023..2819.361 rows=30005836 loops=3) -> Seq Scan on order_line ref_1 (cost=0.00..2011503.04 rows=90017504 width=8) (actual time=0.001..0.001 rows=1 loops=90017507) Planning Time: 0.334 ms Execution Time: 74110.942 ms