PostgreSQL 与关系代数 (Equi-Join , Semi-Join , Anti-Join , Division)

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介:

标签

PostgreSQL , 关系代数 , EquiJoin , SemiJoin , AntiJoin , Division


背景

关系数据库中很多操作来自关系代数中的一些概念。例如常见的JOIN操作,下面是关系代数中的一些概念。

https://en.wikipedia.org/wiki/Relational_algebra

JOIN本身也分好多种比如EquiJoin , SemiJoin , AntiJoin , Division。

EquiJoin

这种JOIN最为常见。例如:

select a.* from a join b on (a.xx = b.xx);  

实际上关系代数中为θ-join,包括(<, ≤, =, >, ≥),当使用=时,对应的就是equijoin.

只要操作符(JOIN条件)返回TRUE,就输出对应的JOIN记录。(也可以理解为笛卡尔乘积中,仅返回JOIN条件为TRUE的那些)

SemiJoin

返回在Employee中的记录,同时这条记录与Dept中的所有记录一对多操作时,有一个返回TRUE的操作即可。

例如

select * from Employee where exists   
  (select 1 from Dept where Employee.DeptName = Dept.DeptName);  -- 现实中操作符可以随意替代,代表不同语义  

pic

由于semiJoin的操作在EXISTS中只要有一条符合TRUE即可,所以很大概率下并不需要扫描全量Dept。

semiJOIN支持hash, merge, nestloop几种JOIN方法。

Employee很小,并且Dept有索引时,NESTLOOP就会比较快。

Employee很大时,使用hash就很快。

PostgreSQL 11在hash操作上有了极大的性能提升:

《PostgreSQL 11 preview - parallel hash (含hash JOIN , hash agg等) 性能极大提升》

《PostgreSQL dblink异步调用实现 并行hash分片JOIN - 含数据交、并、差 提速案例》

AntiJoin

AntiJoin与SemiJoin表达的意思有点相反,要求Employee中的每一条记录,与Dept中所有记录进行操作后,Dept中没有任何一条能满足。返回在Employee中的这样的记录。

例如

select * from Employee where not exists   
  (select 1 from Dept where Employee.DeptName = Dept.DeptName);   -- 现实中操作符可以随意替代,代表不同语义  

pic

AntiJoin要求Employee中每一条记录与Dept所有记录进行操作,并且所有操作都不满足条件,这条算作有效记录,返回该Employee的记录。

对于JOIN操作符为=号的,不管是semijoin还是antijoin,都可以用HASH join,达到非常好的加速效果。

Division

JOIN中的除法运算,没有对应的SQL,需要写多条SQL或者使用CTE语法写一条SQL来实现。

pic

pic

1、补齐

tmp1:

select Student, Task from  
(  
  select distinct Student from Completed  
) t1   
,  
(  
  select Task from DBProject  
) t2;  

2、使用AntiJoin计算余数

tmp2:

select Student from Completed where not exists   
  (select 1 from tmp1 where tmp1.Student=Completed.Student and tmp1.Task=Completed.Task);  

3、去重,并使用except求差,得到最终结果

select distinct Student from Completed   
except  
select Student from tmp2;  

pic

CTE实现Division

with   
  t1 as (select distinct Student as Student from Completed),  
  tmp1 as (select Student, Task from t1, (select Task from DBProject) t2),  
  tmp2 as (select Student from Completed where not exists   
              (select 1 from tmp1 where tmp1.Student=Completed.Student and tmp1.Task=Completed.Task)  
	  )  
select Student from t1  
except  
select Student from tmp2;  

除法求余

outerjoin不再赘述。

Paralle HASH JOIN (equijoin, semijoin, antijoin)性能指标

PostgreSQL 11

64线程机器,使用HASH并行。

测试数据:

postgres=# create table a(id int);  
CREATE TABLE  
  
postgres=# create table b(id int);  
CREATE TABLE  
  
postgres=# insert into a select generate_series(1,100000000);  
INSERT 0 100000000  
  
postgres=# insert into b select generate_series(1,1000000);  
INSERT 0 1000000  

1 Equi-Join

postgres=# explain analyze select count(*) from a join b using (id);  
                                                                   QUERY PLAN                                                                     
------------------------------------------------------------------------------------------------------------------------------------------------  
 Finalize Aggregate  (cost=469787.02..469787.03 rows=1 width=8) (actual time=902.399..902.399 rows=1 loops=1)  
   ->  Gather  (cost=469780.45..469786.86 rows=64 width=8) (actual time=901.209..902.383 rows=65 loops=1)  
         Workers Planned: 64  
         Workers Launched: 64  
         ->  Partial Aggregate  (cost=468780.45..468780.46 rows=1 width=8) (actual time=843.689..843.690 rows=1 loops=65)  
               ->  Parallel Hash Join  (cost=4776.56..468741.38 rows=15625 width=0) (actual time=38.430..842.222 rows=15385 loops=65)  
                     Hash Cond: (a.id = b.id)  
                     ->  Parallel Seq Scan on a  (cost=0.00..458103.01 rows=1562500 width=4) (actual time=0.023..296.974 rows=1538462 loops=65)  
                     ->  Parallel Hash  (cost=4581.25..4581.25 rows=15625 width=4) (actual time=36.133..36.133 rows=15385 loops=65)  
                           Buckets: 1048576  Batches: 1  Memory Usage: 48832kB  
                           ->  Parallel Seq Scan on b  (cost=0.00..4581.25 rows=15625 width=4) (actual time=0.022..2.093 rows=15385 loops=65)  
 Planning time: 0.117 ms  
 Execution time: 990.915 ms  
(13 rows)  

2 Semi-join

postgres=# explain analyze select count(*) from a where exists (select 1 from b where a.id=b.id);  
                                                                   QUERY PLAN                                                                     
------------------------------------------------------------------------------------------------------------------------------------------------  
 Finalize Aggregate  (cost=468200.59..468200.60 rows=1 width=8) (actual time=890.449..890.449 rows=1 loops=1)  
   ->  Gather  (cost=468194.02..468200.43 rows=64 width=8) (actual time=889.040..890.434 rows=65 loops=1)  
         Workers Planned: 64  
         Workers Launched: 64  
         ->  Partial Aggregate  (cost=467194.02..467194.03 rows=1 width=8) (actual time=831.249..831.249 rows=1 loops=65)  
               ->  Parallel Hash Semi Join  (cost=4776.56..467154.96 rows=15625 width=0) (actual time=37.204..829.763 rows=15385 loops=65)  
                     Hash Cond: (a.id = b.id)  
                     ->  Parallel Seq Scan on a  (cost=0.00..458103.01 rows=1562500 width=4) (actual time=0.024..289.738 rows=1538462 loops=65)  
                     ->  Parallel Hash  (cost=4581.25..4581.25 rows=15625 width=4) (actual time=35.672..35.672 rows=15385 loops=65)  
                           Buckets: 1048576  Batches: 1  Memory Usage: 48896kB  
                           ->  Parallel Seq Scan on b  (cost=0.00..4581.25 rows=15625 width=4) (actual time=0.023..2.090 rows=15385 loops=65)  
 Planning time: 0.132 ms  
 Execution time: 980.261 ms  
(13 rows)  

3 Anti-Join

postgres=# explain analyze select count(*) from a where not exists (select 1 from b where a.id=b.id);  
                                                                   QUERY PLAN                                                                     
------------------------------------------------------------------------------------------------------------------------------------------------  
 Finalize Aggregate  (cost=487341.22..487341.23 rows=1 width=8) (actual time=1171.201..1171.201 rows=1 loops=1)  
   ->  Gather  (cost=487334.65..487341.06 rows=64 width=8) (actual time=1169.676..1171.185 rows=65 loops=1)  
         Workers Planned: 64  
         Workers Launched: 64  
         ->  Partial Aggregate  (cost=486334.65..486334.66 rows=1 width=8) (actual time=1110.487..1110.487 rows=1 loops=65)  
               ->  Parallel Hash Anti Join  (cost=4776.56..482467.46 rows=1546876 width=0) (actual time=53.768..964.692 rows=1523077 loops=65)  
                     Hash Cond: (a.id = b.id)  
                     ->  Parallel Seq Scan on a  (cost=0.00..458103.01 rows=1562500 width=4) (actual time=0.023..288.519 rows=1538462 loops=65)  
                     ->  Parallel Hash  (cost=4581.25..4581.25 rows=15625 width=4) (actual time=35.322..35.322 rows=15385 loops=65)  
                           Buckets: 1048576  Batches: 1  Memory Usage: 48864kB  
                           ->  Parallel Seq Scan on b  (cost=0.00..4581.25 rows=15625 width=4) (actual time=0.022..2.010 rows=15385 loops=65)  
 Planning time: 0.129 ms  
 Execution time: 1259.454 ms  
(13 rows)  

小结

PostgreSQL的JOIN算法可圈可点,在版本11后,引入了parallel hash join,支持equijoin, semijoin, antijoin等各种关系计算。

性能杠杠的。

参考

https://en.wikipedia.org/wiki/Relational_algebra

https://www.postgresql.org/message-id/flat/CAEepm=270ze2hVxWkJw-5eKzc3AB4C9KpH3L2kih75R5pdSogg@mail.gmail.com#CAEepm=270ze2hVxWkJw-5eKzc3AB4C9KpH3L2kih75R5pdSogg@mail.gmail.com

http://blog.itpub.net/15480802/viewspace-703260/

《PostgreSQL 11 preview - parallel hash (含hash JOIN , hash agg等) 性能极大提升》

《PostgreSQL dblink异步调用实现 并行hash分片JOIN - 含数据交、并、差 提速案例》

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
2月前
|
算法 关系型数据库 MySQL
浅析MySQL Join Reorder算法
本文浅析了MySQL Join Reorder算法的流程,cost计算,剪枝算法等,希望通过本文能帮助大家了解MySQL优化器生成执行计划的具体流程。
openGauss向量化Merge Join--semi join
openGauss向量化Merge Join--semi join
92 0
|
6月前
|
SQL Oracle 关系型数据库
Oracle查询优化-left join、right join、inner join、full join和逗号的区别
【1月更文挑战第5天】【1月更文挑战第13篇】实际查询时,多表联查是常规操作,但是连接方式有多种。
527 0
Hive中的in、exists和left semi join
Hive中的in、exists和left semi join
Hive中的in、exists和left semi join
|
关系型数据库 MySQL 数据库
MySQL inner join on、外连接、left join、right join
MySQL inner join on、外连接、left join、right join
156 0
MySQL inner join on、外连接、left join、right join
|
SQL Oracle 关系型数据库
SQL99中的natural join 和 using
natural join 叫自然连接,是SQL99语法中支持的一种连接方式,mysql与oracle等主流数据库均支持这种语法。natural join 无需声明连接条件,sql执行器会自动寻找连接的两个表中相同的字段去生成连接条件,然后取数据的交集。
228 0
|
SQL 数据库
SQL中关于Join、Inner Join、Left Join、Right Join、Full Join、On、 Where区别
SQL中关于Join、Inner Join、Left Join、Right Join、Full Join、On、 Where区别
136 0
SQL中关于Join、Inner Join、Left Join、Right Join、Full Join、On、 Where区别
|
SQL 关系型数据库 MySQL
MySQL - LEFT JOIN、RIGHT JOIN、INNER JOIN、CROSS JOIN、FULL JOIN
MySQL - LEFT JOIN、RIGHT JOIN、INNER JOIN、CROSS JOIN、FULL JOIN
460 0
MySQL - LEFT JOIN、RIGHT JOIN、INNER JOIN、CROSS JOIN、FULL JOIN
|
分布式计算 MaxCompute 索引
【转载】MaxCompute full outer join改写left anti join实践
ods层数据同步时经常会遇到增全量合并的模型,即T-1天增量表 + T-2全量表 = T-1全量表。可以通过full outer join脚本来完成合并,但是数据量很大时非常消耗资源。本文将为您介绍在做增量数据的增加、更新时如何通过full outer join改写left anti join来实现的最佳实践。
12875 0
【转载】MaxCompute full outer join改写left anti join实践
|
SQL 存储 弹性计算
PostgreSQL sharding extensino citus 优化器 Query Processing 之 - Subquery/CTE Push-Pull Execution
标签 PostgreSQL , citus , sharding , push , pull , 优化器 背景 citus 是postgresql的sharding 开源中间件,2018年被微软收购,插件依旧开源。 在处理非常复杂的SQL时,CITUS使用推拉模型,支持跨节点的数据交换,用以处理复杂SQL。 中间结果的push,pull过程: push : shard ->
278 0