第1章 与SQL优化相关的几个案例
案例1 一条SQL引发的血案
1.案例说明
某大型电商公司数据仓库系统,正常情况下每天凌晨0~9点会执行大量作业生成前一天的业务报表,供管理层分析使用。但某天早晨6点开始,监控人员就频繁收到业务报警,大批业务报表突然出现大面积延迟。原本8点前就应跑出的报表,一直持续到10点仍然没有结果。公司领导非常重视,严令在11点前必须解决问题。
DBA紧急介入处理,通过TOP命令查看到某个进程占用了大量资源,杀掉后不久还会再次出现。经跟开发人员沟通,这是由于调度机制所致,非正常结束的作业会反复执行。暂时设置该作业无效,并从脚本中排查可疑SQL。同时对比从线上收集的ASH/AWR报告,最终定位到某条SQL比较可疑,经跟开发人员确认系一新增功能,因上线紧急,只做了简单的功能测试。正是因为这一条SQL,导致整个系统运行缓慢,大量作业受到影响,修改SQL后系统恢复正常。
具体分析:
SELECT /*+ INDEX (A1 xxxxx) */ SUM(A2.CRKSL), SUM(A2.CRKSL*A2.DJ) ... FROM xxxx A2, xxxx A1 WHERE A2.CRKFLAG=xxx AND A2.CDATE>=xxx AND A2.CDATE<xxx;
这是一个很典型的两表关联语句,两张表的数据量都较大。下面来看看执行计划,如图1-1所示。
图1-1 执行计划
执行计划触目惊心,优化器评估返回的数据量为3505T条记录,计划返回量127P字节,总成本9890G,返回时间999:59:59。
分析结论:从执行计划中可见,两表关联使用了笛卡儿积的关联方式。我们知道笛卡儿连接是指在两表连接没有任何连接条件的情况。一般情况下应尽量避免笛卡儿积,除非某些特殊场合。否则再强大的数据库,也无法处理。这是一个典型的多表关联缺乏连接条件,导致笛卡儿积,引发性能问题的案例。
2.给我们的启示
从案例本身来讲,并没有什么特别之处,不过是开发人员疏忽,导致了一条质量很差的SQL。但从更深层次来讲,这个案例可以给我们带来如下启示:
- 开发人员的一个疏忽,造成了严重的后果,原来数据库竟是如此的脆弱。需要对数据库保持一种“敬畏”之心。
- 电脑不是人脑,它不知道你的需求是什么,只能根据写好的逻辑进行处理。
- 不要去责怪开发人员,谁都会犯错误,关键是如何从制度上保证不再发生类似的问题。
3.解决之道
(1)SQL开发规范
加强对数据库开发人员的培训工作,提高其对数据库的理解能力和SQL开发水平。将部分SQL运行检查的职责前置,在开发阶段就能规避很多问题。要向开发人员灌输SQL优化的思想,在工作中逐步积累,这样才能提高公司整体开发质量,也可以避免很多低级错误。
(2)SQL Review制度
对于SQL Review,怎么强调都不过分。从业内来看,很多公司也都在自己的开发流程中纳入了这个环节,甚至列为考评范围,对其重视程度可见一斑。其常见典型做法是利用SQL分析引擎(商用或自研)进行分析或采取半人工的方式进行审核。对于审核后的结果,可作为持续改进的依据。SQL Review的中间结果可以保留,作为系统上线后的对比分析依据,进而可将SQL的审核、优化、管理等功能集成起来,完成对SQL整个生命周期的管理。
(3)限流/资源控制
有些数据库提供了丰富的资源限制功能,可以从多个维度限制会话对资源(CPU、MEMORY、IO)的使用。可避免发生单个会话影响整个数据库的运行状态。对于一些开源数据库,部分技术实力较强的公司,还通过对内核的修改实现了限流功能,控制资源消耗较多的SQL运行数量,从而避免拖慢数据库的整体运行。