postgresql 复杂连接上的并行顺序扫描

egdjgwm8  于 2023-03-08  发布在  PostgreSQL
关注(0)|答案(1)|浏览(138)

我有以下SQL(简化和匿名,以便更容易理解)

select max(db.tableA."id")
from db.tableA
         left outer join db.tableB
                         on (db.tableB.column1 = db.tableA.column1
                            and db.tableB.column2 = db.tableA.column2
                            and db.tableB.column3 = db.tableA.column3
                            and db.tableB.column4 = db.tableA.column4)
where (db.tableA.column1 = 'SOME_VALUE'
       and db.tableA.column2 in ('some', 'list', 'of', 'values')
       and db.tableB.column2 is null)

由于某些原因,这个SQL有时甚至运行20秒。当我使用EXPLAIN ANALYZE时,我看到一些我不太理解的东西。

->  Partial Aggregate  (cost=11704.05..11704.06 rows=1 width=8) (actual time=62.069..62.110 rows=1 loops=5)
              ->  Hash Anti Join  (cost=34.58..11679.12 rows=9970 width=8) (actual time=62.064..62.105 rows=0 loops=5)
                    Hash Cond: ((_hyper_1_11005_chunk.column1= tableB.column1) AND (_hyper_1_11005_chunk.column2= tableB.column2) AND (_hyper_1_11005_chunk.column3= tableB.column3) AND (_hyper_1_11005_chunk.column4= tableB.column4))
                    ->  Parallel Append  (cost=0.02..11369.08 rows=11389 width=29) (actual time=0.038..47.278 rows=11262 loops=5)
                          ->  Parallel Seq Scan on _hyper_1_11005_chunk  (cost=0.02..462.20 rows=1667 width=29) (actual time=0.041..13.213 rows=2834 loops=1)
"                                Filter: ((column1= 'SOME_VALUE'::text) AND (column2= ANY ('{'some', 'list', 'of', 'values'}'::text[])))"

此列表还包含大量Parallel Seq Scan步骤(每个步骤都具有相同的条件,只是在另一个块上)

包含上述SQL中任何列的表的索引为(为简单起见,省略了主键的索引)

表A

  • (第1栏、第2栏、第3栏、第4栏)
    表B
  • (第一栏、第二栏)

我可能丢失了一些索引或其他东西,因为我认为这个SQL运行几秒钟并不复杂,但我不知道我丢失了什么,有人能帮我理解为什么PostgreSQL使用多个顺序扫描将这些表连接在一起吗?

PostgreSQL版本为14.5
**编辑:**根据要求,详细分析结果、设置、缓冲区如下所示(由于长度为Explain result,通过pastebin粘贴)

6mzjoqzu

6mzjoqzu1#

正如我所写的,如果clomun2总是有值,您可以尝试

select max(db.tableA."id")
from db.tableA       
where (db.tableA.column1 = 'SOME_VALUE'
       and db.tableA.column2 in ('some', 'list', 'of', 'values')
       and NOT EXISTS( SELECT 1 FROM  db.tableB
                         WHERE (db.tableB.column1 = db.tableA.column1
                            and db.tableB.column2 = db.tableA.column2
                            and db.tableB.column3 = db.tableA.column3
                            and db.tableB.column4 = db.tableA.column4))

如果这样做还不够快的话,您可以将IN子句与SELECT s和UNION ALL分开,这样就可以避免完整扫描,当然只有在列表很小时才可以这样做

相关问题