PostgreSQL 提升子连接和 ORACLE 子查询展开

时间:2023-03-18
本文章向大家介绍PostgreSQL 提升子连接和 ORACLE 子查询展开,主要内容包括一、需要了解的概念:、二、in 子连接、使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

查询优化器对子查询一般采用嵌套执行的方式,即父查询中的每一行,都要执行一次子查询,这样子查询会执行很多次,效率非常低。
例如 exists、not exists 逐行取出经行匹配处理,项目中使用子查询的地方非常多,如何写出高效的sql,掌握子查询的优化是非常有必要的。

一、需要了解的概念:

PostgreSQL数据库基于子查询所在的位置和作用的不同,将子查询细分成了两类,一类称为子连接(SubLink),另一类称为子查询(SubQuery)。
如何区分子连接和子查询?
通常而言,如果它是以范围表的方式存在的,那么就称为子查询。

explain
select e1.*
from emp e1,
     (select * from emp where deptno = 10) e2
where e1.empno = e2.empno

Hash Join  (cost=1.21..2.40 rows=3 width=41)
  Hash Cond: (e1.empno = emp.empno)
  ->  Seq Scan on emp e1  (cost=0.00..1.14 rows=14 width=41)
  ->  Hash  (cost=1.18..1.18 rows=3 width=5)
        ->  Seq Scan on emp  (cost=0.00..1.18 rows=3 width=5)
              Filter: (deptno = '10'::numeric)

如果它以表达式的方式存在,那么就称为子连接。

-- 子链接1
explain
select e.empno, (select avg(sal) from emp e1 where e.deptno = e1.deptno)
from emp e

Seq Scan on emp e  (cost=0.00..17.94 rows=14 width=37)
  SubPlan 1
    ->  Aggregate  (cost=1.19..1.20 rows=1 width=32)
          ->  Seq Scan on emp e1  (cost=0.00..1.18 rows=5 width=5)
                Filter: (e.deptno = deptno)


-- 子链接2
explain
select *
from emp e1
where sal in (select sal from emp where e1.deptno = 10)

Seq Scan on emp e1  (cost=0.00..9.43 rows=7 width=41)
  Filter: (SubPlan 1)
  SubPlan 1
    ->  Result  (cost=0.00..1.14 rows=14 width=5)
          One-Time Filter: (e1.deptno = '10'::numeric)
          ->  Seq Scan on emp  (cost=0.00..1.14 rows=14 width=5)

一般情况下,子连接的执行效率往往是比子查询低很多,因为子连接是逐行处理,会产生filter,而PostgreSQL 优化器会在某些情况下对子连接进行提升为子查询,从而对filter操作进行消除,提升查询效率。

二、in 子连接

** in 子连接提升子查询写法:**

explain select * from emp where deptno in (select deptno from dept);

Hash Join  (cost=1.09..2.31 rows=14 width=41)
  Hash Cond: (emp.deptno = dept.deptno)
  ->  Seq Scan on emp  (cost=0.00..1.14 rows=14 width=41)
  ->  Hash  (cost=1.04..1.04 rows=4 width=5)
        ->  Seq Scan on dept  (cost=0.00..1.04 rows=4 width=5)


可以被提升,优化器相会内部重写成内连接。

explain select emp.* from emp inner join dept on emp.deptno = dept.deptno;

Hash Join  (cost=1.09..2.31 rows=14 width=41)
  Hash Cond: (emp.deptno = dept.deptno)
  ->  Seq Scan on emp  (cost=0.00..1.14 rows=14 width=41)
  ->  Hash  (cost=1.04..1.04 rows=4 width=5)
        ->  Seq Scan on dept  (cost=0.00..1.04 rows=4 width=5)

表明此 in 子连接被优化,优化后采用hash join算法。

in 子连接无法提升子查询写法:

explain select * from emp e1 where sal in (select sal from emp where e1.deptno = 10);

Seq Scan on emp e1  (cost=0.00..9.43 rows=7 width=41)
  Filter: (SubPlan 1)
  SubPlan 1
    ->  Result  (cost=0.00..1.14 rows=14 width=5)
          One-Time Filter: (e1.deptno = '10'::numeric)
          ->  Seq Scan on emp  (cost=0.00..1.14 rows=14 width=5)
explain select * from emp e1 where sal not in (select sal from emp );

Seq Scan on emp e1  (cost=1.18..2.35 rows=7 width=41)
  Filter: (NOT (hashed SubPlan 1))
  SubPlan 1
    ->  Seq Scan on emp  (cost=0.00..1.14 rows=14 width=5)

表明此 in 子连接未被优化,无法消除filter操作,只能逐行处理。

原文地址:https://www.cnblogs.com/yuzhijian/p/17229200.html