杀手SQL- 一条关于 'Not in' SQL 的优化案例

编辑手记:在 DBA 所优化的数据库环境中,绝大多数性能问题其实是由于 SQL 编写不当导致的。SQL 的世界无奇不有,今天我们一起见识一条让你绝对想吐血的杀手SQL。

某保险客户,ETL 耗时数个小时,我们做了sql report发现压力主要在其中一个SQL上。

单次执行时间:5788(秒)

单次逻辑读:10亿(块)

单次返回行数:21万(行)

我们首先看SQL语句,因为比较长,此处只节选部分的

查看其执行计划:

我们主要关注一下从7到16行:发现存在两次全表扫描。中间做了一次filter。

多年的经验告诉我,两个全表扫组成的Filter ,问题很严重, 因为涉及数据逐条处理。 而这个执行计划里,被驱动表还是全表扫。

Not In/In 操作有时候的确会产生 Filter操作,在11g之前的版本,要把not in 语句转换成反连接,not in条件的列必须有Not null 属性,或者语句中带入了not null的限制,否则只能采用Filter,逐条过滤.

我们举例说明一下:

SQL1:CREATE TABLE T_OBJ AS SELECT OBJECT_ID,OWNER,OBJECT_NAME,OBJECT_TYPE FROM DBA_OBJECTS WHERE OWNER != 'SEROL';

SQL2:CREATE TABLET_TABLE AS SELECT OWNER,TABLE_NAME FROM DBA_TABLES WHERE OWNER!='SEROL';

查看T_OBJ的属性:

发现有在三列上都没有not null的限制。

我们此时伪装成10G的优化器。

SQL> alter session set optimizer_features_enable="10.2.0.5";

执行以下SQL:

SQL> set autotracetrace exp

SQL> SELECT * FROM T_TABLE WHERE TABLE_NAME NOT IN(SELECT OBJECT_NAME FROM T_OBJ);

此时查看执行计划,我们发现走的是filter:

但在11g版本中,优化器可以自动把Not in操作从昂贵的Filter转换成Null-Aware-Anti-Join。

若加个Not null 条件或者栏位属性设为not null

SQL> alter table T_OBJ modify(OBJECT_NAME NOT NULL);

再次执行相同语句:

SQL> SELECT * FROM T_TABLE  WHERE TABLE_NAME

NOT IN(SELECT OBJECT_NAME FROM T_OBJ

WHEREOBJECT_NAME IS NOT NULL);

再次查看执行计划:

此时我们发现,在执行计划中,走了hash join anti.

并且,在11g里面,允许not in列没有not null 限制也可以转换Anti-Join.

SQL> alter session set optimizer_features_enable="11.2.0.4";

SQL> alter table T_OBJ modify(OBJECT_NAME NULL);

SQ>  SELECT * FROM T_TABLE  WHERE TABLE_NAME

NOT IN (SELECTOBJECT_NAMEFROM T_OBJ);

查看执行计划:

我们看到,此时在没有非空限制的情况下,也走了hash join anti.

这个特性, 可通过优化器参数控制。

SQL>alter session set "_optimizer_null_aware_antijoin"=FALSE;

再次执行以上语句并查看执行计划:

SQL>  SELECT * FROM T_TABLE  WHERE TABLE_NAME

NOT IN (SELECTOBJECT_NAMEFROM T_OBJ);

发现仍然走的是hash join anti.

经过验证,不是这个参数设置问题

Not in 的逻辑,就是结果集之间的互斥,其实有多种改写的方式,比如:

-- Not exists

-- Outer Join + is null

-- Minus

not in与以上三种写法的区别是:not in 是会排斥空值。

我们尝试改写。

接下来正当你以为会发生奇迹的时候,语句报错了!

为什么会报错呢? 

如果我们把该语句转换为not in的方式:

根据not in的逻辑,此时在fee_code前应该加上'A.',当然这也是没有问题的,但是,再次看这条语句就会变成:

由于TMP_APP_xxx_PREM A 中并没有FEE_CODE字段, 所以,Not in 无法自动改成Null Aware ANTI JOIN。

所以,至此答案揭晓,竟然是写错了?!我猜中了这开头,却没有猜中这结局。

但在本案例中,由于SQL语句中没有显式写出表明,导致在前期分析过程中一直没有发现这个错误。

你是不是也很无语,其实我更想问的是,你是不是也经常写出杀手SQL呢,但没关系,你有病我有药啊。(无辜脸,不要打我)

我们都知道,在 DBA 所优化的数据库环境中,绝大多数性能问题其实是由于 SQL 编写不当导致的。

SQL审核
SQL审核将 SQL 质量审核和优化这项任务,从 DB 端提取到研发端,通过擅长 SQL 的开发 DBA 和开发团队一起修正系统的 SQL,找出问题、修复问题,提升系统的健壮性和稳定性,从而保证整个系统的运维建设质量。

对于未上线系统,通过前期的SQL审核管控,将80%的SQL问题消灭在萌生阶段,对于线上运行系统,发现和解决潜在的性能问题,可做到提前预防,防患于未然。

SQL审核,让DBA由系统的急救医生转身成为系统的保健医生

1、DBA参与应用代码开发测试过程:给开发人员提供专业的数据库开发及优化建议

2、优化前置:在应用代码上线前根据业务需求设计高效的SQL、索引

3、控制变更风险:预先评估应用开发中表结构变更、SQL变更对运行中应用的影响,确定合适的变更窗口,变更方案。

SQL审核产品工具 - z3 

云和恩墨基于Oracle数据库的SQL审核产品工具 - z3 ,通过内置的算法引擎,可定制的抓取数据库中执行的SQL及其详细数据,通过过滤分析,进行量化的积分趋势展现,并将SQL问题高亮显示,指导程序员的优化分析,并可以通过内置的工作流由DBA进行优化,变更管理同时被内置。

本文出自数据和云公众号,原文链接

时间: 2024-12-01 20:13:13

杀手SQL- 一条关于 'Not in' SQL 的优化案例的相关文章

掌握SQL四条最基本的数据操作语句

数据|语句 掌握sql四条最基本的数据操作语句:insert,select,update和delete. 练掌握sql是数据库用户的宝贵财富.在本文中,我们将引导你掌握四条最基本的数据操作语句-sql的核心功能-来依次介绍比较操作符.选择断言以及三值逻辑.当你完成这些学习后,显然你已经开始算是精通sql了. 在我们开始之前,先使用create table语句来创建一个表(如图1所示).ddl语句对数据库对象如表.列和视进行定义.它们并不对表中的行进行处理,这是因为ddl语句并不处理数据库中实际的

pl sql-pl/sql多条查询语句结果导出

问题描述 pl/sql多条查询语句结果导出 有四条查询统计的语句,现在我想把结果导出去只能手动一个个复制出去,有没有办法能一次性全部导出去. 解决方案 用union all连接四条SQL. select count(discnt_code) from ucr_param.td_b_discnt where discnt_code like '30%' union all select count(discnt_code) from ucr_param.td_b_discnt where disc

一条很复杂的sql语句与n条简单的sql语句比,哪个效率高?

问题描述 都是在连接open以后提交语句,一条复杂语句就是操作全由数据库完成,多条简单点的语句是一部分工作由数据库完成,一部分由C#程序完成 解决方案 解决方案二:自己顶下,大神快来解决方案三:肯定是一条啊解决方案四:引用2楼lstcyzj的回复: 肯定是一条啊 如果是操作很复杂不会影响性能么解决方案五:多条简单点的语句其实就是把一些计算放在程序里做了,查询和更新用的sql语句解决方案六:自己顶下,,,,解决方案七:引用3楼newlovedew的回复: 如果是操作很复杂不会影响性能么 这真不能一

求大神帮我写一条查询增量的sql语句

问题描述 求大神帮我写一条查询增量的sql语句 如图,我有这些字段,每天都会插入一些数据 我现在需要获取的内容是 今天的read,click数据,和今天的减昨天的差值,和aid,规则如图 求大神帮我写一个 解决方案 SELECT SUM(d.read_num) AS READ, SUM(d.click_num) AS click, SUM(d.read_num - t.read_num) AS diffREAD, SUM(d.click_num - t.click_num) AS diffcli

读取数据表中第m条到第n条的数据,SQL语句怎么写?

原文:读取数据表中第m条到第n条的数据,SQL语句怎么写? 对于MySQL或者Oracle来说,如果实现从Table 表中取出第 m 条到第 n 条的记录操作,我们需要TOP函数(不是所有的数据库都支持TOP函数):Select Top子句 但是,你能想到几种方法? (1)使用not in Select TOP n-m+1 *  FROM Table  Where (id NOT IN (Select TOP m-1 id FROM Table ))     (2)使用exists  Selec

在SQL SERVER中查询数据库中第几条至第几条之间的数据SQL语句写法_数据库其它

今天在写程序的时候,需要生成从开始id到结束id的sql语句.原来不需要这个功能现在就需要了. 在SQL SERVER中查询数据库中第几条至第几条之间的数据SQL语句如何写? 如:在SQL SERVER中查询数据库中第10条至30条之间的数据SQL语句如何写? ------解决方案-------------------- select top 20 * from 表 where id in (select top 30 id from 表 order by id)order by id desc

探讨如何在有着1000万条数据的MS SQL SERVER数据库中实现快速的数据提取和数据分页

探讨如何在有着1000万条数据的MS SQL SERVER数据库中实现快速的数据提取和数据分页.以下代码说明了我们实例中数据库的一表的部分数据结构: CREATE TABLE [dbo].[TGongwen] (    --TGongwen是红头文件表名    [Gid] [int] IDENTITY (1, 1) NOT NULL ,--本表的id号,也是主键    [title] [varchar] (80) COLLATE Chinese_PRC_CI_AS NULL ,  --红头文件的

一名小小的SQL Server DBA想谈一下SQL Server的能力

原文:一名小小的SQL Server DBA想谈一下SQL Server的能力 一名小小的SQL Server DBA想谈一下SQL Server的能力 百度上暂时还没有搜索到相关的个人写的比较有价值的文章至少在中文网络的世界里面没有 但是在微软的网站有这样一篇文章<比较 SQL Server 与 IBM DB2> 文章从下面几个方面进行了对比 1.TCO和ROI2.性能和可扩展性3.高可用性4.安全5.管理6.开发效率7.商业智能和数据仓库8.OLTP9.SAP集成 文章介绍得比较牛逼 性能

SQL Server审计功能入门:SQL Server审核 (SQL Server Audit)

原文:SQL Server审计功能入门:SQL Server审核 (SQL Server Audit) 介绍     Audit是SQL Server 2008之后才有的功能,它能告诉你"谁什么时候做了什么事情".具体是指审核SQL Server 数据库引擎实例或单独的数据库涉及到跟踪和记录数据库引擎中发生的事件.它的底层是基于扩展事件(Extented Event),所以其性能和灵活性相对较好.审核数据可以输出到审核文件.Windows安全日志和应用程序日志.     Audit都需