今天遇到一个性能问题,再调优过程中发现耗时最久的计划是exist 部分涉及的三个表。

然后计划用left join 来替换exist,然后查询了很多资料,大部分都说exist和left join 性能差不多。 为了验证这一结论进行了如下实验

步骤如下

1、创建测试表

drop table app_family;

CREATE TABLE app_family (

"family_id" character varying(32 char) NOT NULL,

"application_id" character varying(32 char) NULL,

"family_number" character varying(50 char) ,

"household_register_number" character varying(50 char),

"poverty_reason" character varying(32 char),

CONSTRAINT "pk_app_family_idpk" PRIMARY KEY (family_id));

insert into app_family select generate_series(1,1000000),generate_series(1,1000000),'aaaa','aaa','bbb' from dual ;

create table app_family2 as select * from app_family;

create table app_memeber as select * from app_family;

2、验证两张表join和exist 性能对比

语句1、两张表exist

explain analyze select a1.application_id,a1.family_id from app_family a1 where

a1.family_id >1000 and

EXISTS(

SELECT

1

FROM

app_family2 a2

WHERE

a2.application_id=a1.application_id

and a2.family_id > 500000

)

总计用时646.203 ms

 ----------------------------------------------------------------------------------------------------------------------------------------------------
Gather (cost=16927.11..44466.84 rows=111111 width=12) (actual time=354.314..621.714 rows=500000 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Parallel Hash Semi Join (cost=15927.11..32355.74 rows=46296 width=12) (actual time=355.657..512.049 rows=166667 loops=3)
Hash Cond: ((a1.application_id)::text = (a2.application_id)::text)
-> Parallel Seq Scan on app_family a1 (cost=0.00..13648.00 rows=138889 width=12) (actual time=0.222..111.618 rows=333000 loops=3)
Filter: ((family_id)::integer > 1000)
Rows Removed by Filter: 333
-> Parallel Hash (cost=13648.00..13648.00 rows=138889 width=6) (actual time=149.203..149.204 rows=166667 loops=3)
Buckets: 131072 Batches: 8 Memory Usage: 3520kB
-> Parallel Seq Scan on app_family2 a2 (cost=0.00..13648.00 rows=138889 width=6) (actual time=48.576..109.251 rows=166667 loops=3)
Filter: ((family_id)::integer > 500000)
Rows Removed by Filter: 166667
Planning Time: 0.145 ms
Execution Time: 645.095 ms
(15 rows) Time: 646.203 ms
kingbase=#

语句2 两张表join

explain analyze select a1.application_id,a1.family_id from app_family a1 LEFT JOIN app_family2 a2 ON a2.application_id=a1.application_id

WHERE a1.family_id >1000 AND a2.family_id > 500000

总计执行时间624.211 ms

---------------------------------------------------------------------------------------------------------------------------------------------------
Gather (cost=16927.11..44300.95 rows=111111 width=12) (actual time=349.752..601.304 rows=500000 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Parallel Hash Join (cost=15927.11..32189.85 rows=46296 width=12) (actual time=337.548..508.139 rows=166667 loops=3)
Hash Cond: ((a1.application_id)::text = (a2.application_id)::text)
-> Parallel Seq Scan on app_family a1 (cost=0.00..13648.00 rows=138889 width=12) (actual time=0.087..111.949 rows=333000 loops=3)
Filter: ((family_id)::integer > 1000)
Rows Removed by Filter: 333
-> Parallel Hash (cost=13648.00..13648.00 rows=138889 width=6) (actual time=131.718..131.719 rows=166667 loops=3)
Buckets: 131072 Batches: 8 Memory Usage: 3488kB
-> Parallel Seq Scan on app_family2 a2 (cost=0.00..13648.00 rows=138889 width=6) (actual time=31.730..90.917 rows=166667 loops=3)
Filter: ((family_id)::integer > 500000)
Rows Removed by Filter: 166667
Planning Time: 0.093 ms
Execution Time: 623.465 ms
(15 rows) Time: 624.211 ms

两张表场景总结

针对两张表的对比可以发现join还相对满了10几ms但是总的来说两边 差异不大。所以再两张表的关联情况下 join和exist 性能相近。

3、验证3张表join和exist 性能对比

语句1 三张表exist

本场景最开始执行时 exit 用户6 s多,原因时用到了内存排序,后来调整了work_mem 排除了内存排序的影响,最终执行时间

2911.146 ms

explain analyze select a1.application_id,a1.family_id from app_family a1 ,app_family2 a2 where

a1.family_id >1000 and a2.family_id < 900000 and

EXISTS(

SELECT

1

FROM

app_memeber m

WHERE

m.application_id=a1.application_id

and m.family_id=a2.family_id

)

------------------------------------------------------------------------------------------------------------------------------------------------------
--
Gather (cost=61282.11..88664.67 rows=111111 width=12) (actual time=2112.079..2847.233 rows=898999 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Parallel Hash Join (cost=60282.11..76553.57 rows=46296 width=12) (actual time=2119.345..2705.935 rows=299666 loops=3)
Hash Cond: ((m.family_id)::text = (a2.family_id)::text)
-> Hash Join (cost=44898.00..60455.72 rows=138889 width=18) (actual time=1885.923..2264.850 rows=333000 loops=3)
Hash Cond: ((a1.application_id)::text = (m.application_id)::text)
-> Parallel Seq Scan on app_family a1 (cost=0.00..13648.00 rows=138889 width=12) (actual time=0.091..109.196 rows=333000 loops=3)
Filter: ((family_id)::integer > 1000)
Rows Removed by Filter: 333
-> Hash (cost=32398.00..32398.00 rows=1000000 width=12) (actual time=1880.027..1880.028 rows=1000000 loops=3)
Buckets: 1048576 Batches: 1 Memory Usage: 52897kB
-> HashAggregate (cost=22398.00..32398.00 rows=1000000 width=12) (actual time=957.973..1382.683 rows=1000000 loops=3)
Group Key: (m.application_id)::text, (m.family_id)::text
-> Seq Scan on app_memeber m (cost=0.00..17398.00 rows=1000000 width=12) (actual time=0.047..247.902 rows=1000000 loops=3
)
-> Parallel Hash (cost=13648.00..13648.00 rows=138889 width=6) (actual time=231.705..231.706 rows=300000 loops=3)
Buckets: 1048576 (originally 524288) Batches: 1 (originally 1) Memory Usage: 47552kB
-> Parallel Seq Scan on app_family2 a2 (cost=0.00..13648.00 rows=138889 width=6) (actual time=0.039..100.756 rows=300000 loops=3)
Filter: ((family_id)::integer < 900000)
Rows Removed by Filter: 33334
Planning Time: 0.359 ms
Execution Time: 2911.146 ms
(22 rows)

语句2 三张表join

为了保证语句的一致性,三张表的join顺序保持和语句1的执行计划中的顺序一致,join总计用时1476.651 ms

explain analyze select a1.application_id,a1.family_id from app_family a1

left join app_memeber m on a1.application_id = m.application_id LEFT JOIN app_family2 a2 ON m.family_id = a2.family_id

WHERE a1.family_id >1000 AND a2.family_id < 900000

 Gather  (cost=32990.22..64898.93 rows=111111 width=12) (actual time=993.681..1436.895 rows=898999 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Parallel Hash Join (cost=31990.22..52787.83 rows=46296 width=12) (actual time=982.512..1241.385 rows=299666 loops=3)
Hash Cond: ((m.application_id)::text = (a1.application_id)::text)
-> Parallel Hash Join (cost=15927.11..34245.98 rows=138889 width=6) (actual time=377.411..635.945 rows=300000 loops=3)
Hash Cond: ((m.family_id)::text = (a2.family_id)::text)
-> Parallel Seq Scan on app_memeber m (cost=0.00..11564.67 rows=416667 width=12) (actual time=0.034..59.470 rows=333333 loops=3)
-> Parallel Hash (cost=13648.00..13648.00 rows=138889 width=6) (actual time=232.286..232.287 rows=300000 loops=3)
Buckets: 131072 (originally 131072) Batches: 16 (originally 8) Memory Usage: 3296kB
-> Parallel Seq Scan on app_family2 a2 (cost=0.00..13648.00 rows=138889 width=6) (actual time=0.030..104.370 rows=300000 loops=
3)
Filter: ((family_id)::integer < 900000)
Rows Removed by Filter: 33334
-> Parallel Hash (cost=13648.00..13648.00 rows=138889 width=12) (actual time=271.185..271.185 rows=333000 loops=3)
Buckets: 131072 (originally 131072) Batches: 16 (originally 8) Memory Usage: 4032kB
-> Parallel Seq Scan on app_family a1 (cost=0.00..13648.00 rows=138889 width=12) (actual time=0.091..129.188 rows=333000 loops=3)
Filter: ((family_id)::integer > 1000)
Rows Removed by Filter: 333
Planning Time: 0.140 ms
Execution Time: 1475.305 ms
(20 rows) Time: 1476.651 ms (00:01.477)

总结三张表场景

在三张表的场景下exist用时2911.146 ms ,join用时1476.651 ms 可见 join的顺序明显优于exist。

在三张表的场景下可以看到,针对中间表appmember扫描时, exist语句用到HashAggregate 并做了 Group Key,所以导致exist 执行时间增加。如果work_mem 配置不合适时间会更长。

exist和left join 性能对比的更多相关文章

  1. Go 字符串连接+=与strings.Join性能对比

    Go字符串连接 对于字符串的连接大致有两种方式: 1.通过+号连接 func StrPlus1(a []string) string { var s, sep string for i := 0; i ...

  2. 自己写的轻量级PHP框架trig与laravel5.1,yii2性能对比

    看了下当前最热门的php开发框架,想对比一下自己写的框架与这些框架的性能对比.先看下当前流行框架的投票情况. 看结果对比,每个测试脚本做了一个数据库的联表查询并进行print_r输出,查询的sql语句 ...

  3. SQL点滴10—使用with语句来写一个稍微复杂sql语句,附加和子查询的性能对比

    原文:SQL点滴10-使用with语句来写一个稍微复杂sql语句,附加和子查询的性能对比 今天偶尔看到sql中也有with关键字,好歹也写了几年的sql语句,居然第一次接触,无知啊.看了一位博主的文章 ...

  4. python3下multiprocessing、threading和gevent性能对比----暨进程池、线程池和协程池性能对比

    python3下multiprocessing.threading和gevent性能对比----暨进程池.线程池和协程池性能对比   标签: python3 / 线程池 / multiprocessi ...

  5. SQL Server-聚焦IN VS EXISTS VS JOIN性能分析(十九)

    前言 本节我们开始讲讲这一系列性能比较的终极篇IN VS EXISTS VS JOIN的性能分析,前面系列有人一直在说场景不够,这里我们结合查询索引列.非索引列.查询小表.查询大表来综合分析,简短的内 ...

  6. [原] KVM 环境下MySQL性能对比

    KVM 环境下MySQL性能对比 标签(空格分隔): Cloud2.0 [TOC] 测试目的 对比MySQL在物理机和KVM环境下性能情况 压测标准 压测遵循单一变量原则,所有的对比都是只改变一个变量 ...

  7. 浅谈C++之冒泡排序、希尔排序、快速排序、插入排序、堆排序、基数排序性能对比分析之后续补充说明(有图有真相)

    如果你觉得我的有些话有点唐突,你不理解可以想看看前一篇<C++之冒泡排序.希尔排序.快速排序.插入排序.堆排序.基数排序性能对比分析>. 这几天闲着没事就写了一篇<C++之冒泡排序. ...

  8. Java--Stream,NIO ByteBuffer,NIO MappedByteBuffer性能对比

    目前Java中最IO有多种文件读取的方法,本文章对比Stream,NIO ByteBuffer,NIO MappedByteBuffer的性能,让我们知道到底怎么能写出性能高的文件读取代码. pack ...

  9. C正则库做DNS域名验证时的性能对比

    C正则库做DNS域名验证时的性能对比   本文对C的正则库regex和pcre在做域名验证的场景下做评测. 验证DNS域名的正则表达式为: "^[0-9a-zA-Z_-]+(\\.[0-9a ...

  10. 开发语言性能对比,C++、Java、Python、LUA、TCC

    一直想做开发语言性能对比,刚好有时间都做了给大家参考一下, 编译类:C++和Java表现还不错 脚本类:TCC脚本动态运行C语言,性能比其他脚本快好多... 想玩TCC的同学下载测试包,TCC目录下修 ...

随机推荐

  1. 【OpenGL ES】透视变换原理

    1 前言 ​ MVP矩阵变换 中主要介绍了模型变换(平移.旋转.对称.缩放)和观测变换基本原理,本文将介绍透视变换的基本原理. ​ 如下图,近平面和远平面间棱台称为视锥体,表示可见区域范围,视锥体以外 ...

  2. 《.NET物联网从零开始系列》-开篇

    近日搞硬件网关时,那些残存的数电.模电和通信原理的记忆时常在脑海中萦绕: 想起来多年前看张高兴的博客学会了.netcore+树莓派进行物联网开发. 使用dragonboard(龙板)搭载windows ...

  3. C++ 控制台程序的线程分析

    在无任何功能代码的情况下运行控制台,会发现有三个线程在运行 SO 的答案指出,在程序一开始运行时,为加快进程启动,windows 会利用多个 CPU 内核更快地初始化. ntdll.dll 线程实际上 ...

  4. Go微服务框架go-kratos实战学习08:负载均衡基本使用

    微服务框架 go-kratos 中负载均衡使用 一.介绍 在前面这篇文章 负载均衡和它的算法介绍,讲了什么是负载均衡以及作用.算法介绍. go-kratos 的负载均衡主要接口是 Selector,它 ...

  5. Python输出日志信息

    在Python中要输出日志信息有2种方式: 1.调用内置的print()方法,该方式只能将信息输出到控制台 2.使用logging模块将日志信息输出到文件中(logging模块默认也是输出到控制台:标 ...

  6. ASP.NET XML序列化

    整理一下ASP.NET里面如何序列化实体为XML,获取解析XML内容为实体. 第一步要添加程序集引用,项目-->引用-->鼠标右键-->添加引用-->选择程序集-->Sy ...

  7. C语言变量和数据类型整理

    03-变量和数据类型 3.1 大话C语言变量和数据类型 在<数据在内存中的存储>一节中讲到: ●计算机要处理的数据(诸如数字.文字.符号.图形.音频.视频等)是以二进制的形式存放在内存中的 ...

  8. 【Azure Developer】如何用Microsoft Graph API管理AAD Application里面的Permissions

    问题描述 如何用Microsoft Graph API给应用添加Microsoft Graph Application Permission 解决方法 一:首先获取Microsoft Graph Ap ...

  9. 可视化技术在 Nebula Graph 中的应用

    本文首发于 Nebula Graph Community 公众号 本文整理自 #可视化 on Live 主题直播,在本期直播中 3 位可视化嘉宾讲述了他们眼中的可视化,以及他们在可视化项目实践中踩过的 ...

  10. C++ 函数指针,指针函数,左值右值

    C++ 函数指针,指针函数,左值右值 1.函数指针 是一个指针类型的变量,存放的内容都是函数的指针,用来间接调用函数,格式如下: int add( int a, int b) { return a+b ...