postgresql - 在 PostgreSQL 中如何操作多个子查询的执行顺序?

标签 postgresql subquery execution exists

我的 PostgreSQL 有问题,它的运行时间很长。 这是示例代码。

create table t1 (
cust_id int,
cust_name varchar(100),
comment char(100));
insert into t1 
select i, 'TESTNAME'||i, 'dummyy' from generate_series(1,1000) a(i);
select * from t1;
create table t2
(id int, cust_id int, amount bigint);
insert into t2
select i, case when i < 10 then i else i+1000 end, i*10
  from generate_series(1,100) a(i);
  select * from t2; 

create table t3(
singo_id int, cust_id int, reg_date date, comment char(200));
insert into t3
select i, mod(i,1000), '2021-01-01'::date + mod(i,1000), 'dummyyyy'
  from generate_series(1,2000) a(i);
--I inserted 'offset' to prevent subquery collapse on purpose.
select count(*)
  from t1 a
 where exists (select 1
                 from t3 b
                where reg_date >= '2021-02-02'
                  and a.cust_id = b.cust_id
                offset 0)
   and exists (select 1
                 from t2 c
                where a.cust_id = c.cust_id
                offset 0);

--执行计划

| Aggregate (actual time=8.047..8.048 rows=1 loops=1)                                  |
|   Buffers: shared hit=1568                                                           |
|   ->  Seq Scan on t1 a (actual time=8.042..8.043 rows=0 loops=1)                     |
|         Filter: ((SubPlan 2) AND (SubPlan 1))                                        |
|         Rows Removed by Filter: 1000                                                 |
|         Buffers: shared hit=1568                                                     |
|         SubPlan 2                                                                    |
|           ->  Seq Scan on t2 c (actual time=0.005..0.005 rows=0 loops=1000)          |
|                 Filter: (a.cust_id = cust_id)                                        |
|                 Rows Removed by Filter: 99                                           |
|                 Buffers: shared hit=1000                                             |
|         SubPlan 1                                                                    |
|           ->  Seq Scan on t3 b (actual time=0.293..0.293 rows=0 loops=9)             |
|                 Filter: ((reg_date >= '2021-02-02'::date) AND (a.cust_id = cust_id)) |
|                 Rows Removed by Filter: 2000                                         |
|                 Buffers: shared hit=549  

我知道我做的测试SQL很傻。 我在生产系统中的真实SQL非常复杂,子查询无法折叠。 看上面的执行计划,好像是PostgreSQL先用t2表过滤t1表。 我想让优化器做的是强制优化器首先使用 t3 表进行过滤。 我怎样才能做到这一点? 我将测试 SQL 更改为下面的这个。但它没有用。

select count(*)
  from t1 a
 where exists (select 1
                 from t2 c
                where a.cust_id = c.cust_id
                offset 0)
   and exists (select 1
                 from t3 b
                where reg_date >= '2021-02-02'
                  and a.cust_id = b.cust_id
                offset 0);

最佳答案

没有办法强制顺序 - PostgreSQL 将首先执行它认为在减少行数方面成本更低或更有效的子计划。

你可以做的是使用物化公用表表达式:

WITH subq AS MATERIALIZED (
   SELECT a.id, a.cust_id
   FROM t1 AS a
   WHERE EXISTS (SELECT 1 FROM t3 AS b
                 WHERE b.reg_date >= '2021-02-02'
                   AND a.cust_id = b.cust_id)
)
SELECT count(*)
FROM subq
WHERE EXISTS (SELECT 1 FROM t2 AS c
              WHERE subq.cust_id = c.cust_id);

对于 12 之前的 PostgreSQL 版本,省略 MATERIALIZED

关于postgresql - 在 PostgreSQL 中如何操作多个子查询的执行顺序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67263590/

相关文章:

javascript - "setTimeout(functon(){//do stuff},0)"是否会为其包含的函数导致微小的执行延迟?

arrays - Postgres 对象数组错误 `error: could not determine polymorphic type because input has type "未知”`

sql - 仅从特定的 Postgresql 表中删除重复项

php - mysql查询返回 bool 值但我希望返回id

exception - elasticsearch搜索阶段执行

python - 计算 python 程序的 CPU 时间?

sql - 数据库无法识别创建的函数? SQL状态: 42883

postgresql - 当 psql 具有空白的数据库访问权限时,这意味着什么?

mysql - 对每对求和 mysql 结果

如果没有返回行,MYSQL 可以将 WHERE IN 默认为 ALL