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

简介:

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


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

640?wx_fmt=png&wxfrom=5&wx_lazy=1

单次执行时间:5788(秒)

单次逻辑读:10亿(块)

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


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

640?wx_fmt=png&wxfrom=5&wx_lazy=1


查看其执行计划:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

我们主要关注一下从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的属性:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

发现有在三列上都没有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:

640?wx_fmt=png&wxfrom=5&wx_lazy=1


但在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);


再次查看执行计划:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

此时我们发现,在执行计划中,走了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);


查看执行计划:

640?wx_fmt=png&wxfrom=5&wx_lazy=1


我们看到,此时在没有非空限制的情况下,也走了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);

640?wx_fmt=png&wxfrom=5&wx_lazy=1

发现仍然走的是hash join anti.

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


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

-- Not exists

-- Outer Join + is null

-- Minus

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


我们尝试改写。

640?wx_fmt=png&wxfrom=5&wx_lazy=1


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

640?wx_fmt=png&wxfrom=5&wx_lazy=1


为什么会报错呢? 

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

640?wx_fmt=png&wxfrom=5&wx_lazy=1


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

640?wx_fmt=png&wxfrom=5&wx_lazy=1


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


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

640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

但在本案例中,由于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进行优化,变更管理同时被内置。


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


相关文章
|
20天前
|
SQL 存储 关系型数据库
一文搞懂SQL优化——如何高效添加数据
**SQL优化关键点:** 1. **批量插入**提高效率,一次性建议不超过500条。 2. **手动事务**减少开销,多条插入语句用一个事务。 3. **主键顺序插入**避免页分裂,提升性能。 4. **使用`LOAD DATA INFILE`**大批量导入快速。 5. **避免主键乱序**,减少不必要的磁盘操作。 6. **选择合适主键类型**,避免UUID或长主键导致的性能问题。 7. **避免主键修改**,保持索引稳定。 这些技巧能优化数据库操作,提升系统性能。
215 4
一文搞懂SQL优化——如何高效添加数据
|
1月前
|
SQL 存储 数据库连接
日活3kw下,如何应对实际业务场景中SQL过慢的优化挑战?
在面试中,SQL调优是一个常见的问题,通过这个问题可以考察应聘者对于提升SQL性能的理解和掌握程度。通常来说,SQL调优需要按照以下步骤展开。
|
1月前
|
SQL 关系型数据库 MySQL
【MySQL 数据库】7、SQL 优化
【MySQL 数据库】7、SQL 优化
48 0
|
1月前
|
存储 关系型数据库 MySQL
最全MySQL面试60题(含答案):存储引擎+数据库锁+索引+SQL优化等
最全MySQL面试60题(含答案):存储引擎+数据库锁+索引+SQL优化等
162 0
|
8天前
|
SQL 存储 数据挖掘
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
服务器数据恢复环境: 一台安装windows server操作系统的服务器。一组由8块硬盘组建的RAID5,划分LUN供这台服务器使用。 在windows服务器内装有SqlServer数据库。存储空间LUN划分了两个逻辑分区。 服务器故障&初检: 由于未知原因,Sql Server数据库文件丢失,丢失数据涉及到3个库,表的数量有3000左右。数据库文件丢失原因还没有查清楚,也不能确定数据存储位置。 数据库文件丢失后服务器仍处于开机状态,所幸没有大量数据写入。 将raid5中所有磁盘编号后取出,经过硬件工程师检测,没有发现明显的硬件故障。以只读方式将所有磁盘进行扇区级的全盘镜像,镜像完成后将所
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
|
21天前
|
SQL 关系型数据库 MySQL
【MySQL技术之旅】(7)总结和盘点优化方案系列之常用SQL的优化
【MySQL技术之旅】(7)总结和盘点优化方案系列之常用SQL的优化
36 1
|
22天前
|
SQL 索引
SQL怎么优化
SQL怎么优化
27 2
|
30天前
|
SQL
sql server案例总结
sql server案例总结
11 0
|
30天前
|
SQL 监控 测试技术
SQL语法优化与最佳实践
【2月更文挑战第28天】本章将深入探讨SQL语法优化的重要性以及具体的优化策略和最佳实践。通过掌握和理解这些优化技巧,读者将能够编写出更高效、更稳定的SQL查询,提升数据库性能,降低系统资源消耗。