管好统计信息,开启SQL优化之门

遇到执行效率低下的SQL语句,对于DBA而言无疑是家常便饭了,但如何快速优化,把它变成小菜一碟,则得看看咱们DBA+社群联合发起人卢飞的经验之谈了。

 

专家简介

  

卢飞

DBA+社群联合发起人

 

Oracle 10g OCP,6年Oracle数据库维护经验,对Oracle数据库管理、数据迁移,性能优化有着丰富的实战经验。目前专注于数据库技术及自动化运维方面的研究。

 

在DBA的工作中,SQL优化的工作量占工作很大的一块,我们在平时工作中也是这样,常常遇到一些执行效率低下的SQL语句,而这些执行效率低下的SQL,有的是业务系统刚刚上线的,有的是已经执行很久但因为执行环境变化而导致出现的。这里给大家分享一个SQL的优化案例分析。

 

根据我们监控系统,发现线上OLTP的一个核心业务数据库中有一条SQL执行效率较慢。慢到什么程度?半小时执行278次,平均每次28秒,占用整个DB资源的56%。OLTP系统中,实在太慢了。

 

这里是SQL执行的相关信息。

 

 

 

SQL优化中,有很多人总是第一要看的就是执行计划,那么我们就看看这条SQL的执行计划。下面可以看到单次执行3秒左右,成本为2,consistent gets较高,执行计划中也是走INDEX RANGE SCAN。

 

 

其实单看上面的执行计划Cost还是比较低的,SQL优化中,有很多人总是第一要看的就是执行计划,但是看执行计划一定要结合结构信息,这里的结构信息就是表,索引等结构信息及数据分布信息。

 

我们先看SQL语句吧。以下SQL语句很简单,且在cn字段,c_date字段上都建有索引。

 

 

表数据量约有3.6亿数据。

 

 

在以上执行计划的基础上,根据对业务的理解,我的疑问是为什么不走cn索引?

 

这里其实可以根据谓词条件,各自查询 一下就能看到结果,根据cn查询到3条,而c_date条件查询出76w。走cn索引才对。

 

 

这里也可以使用HINT强制走cn索引看一下效果,使用HINT强制走cn索引后执行时间变为毫秒级。

 

 

 

SQL优化除了了解结构信息(表,索引),统计信息的准确性也很关键。

 

这里发现最后统计信息分析时间是5月份,相差了3个多月,所以统计信息是不正确的。

 

 

统计信息不准确的原因?

 

最终发现Oracle在10g版本中默认的GATHER_STATS_JOB没有启动,这里启动默认的GATHER_STATS_JOB,并单独收集一下表的统计信息。

 

 

 

收集完统计信息,这条SQL的执行时间下降到毫秒级别,执行计划已经变为IDX_REC_LOG_CN索引的RANGE SACN,consistent gets从原来的19409  降低到了7。效果还是很明显。

 

同样的SQL又慢了,现在的执行计划, 又开始走IDX_C_LOG_DATE索引了,而且执行时间又回到了2秒, consistent gets变为10404。以下为执行计划:

 

 

同样我们还是先检查统计信息是否正确,这里可以看到了统计信息又不正确了,但是我们发现GATHER_STATS_JOB每天都能执行成功。这是为什么?

 

 

解决方法就是定义一个单表收集的JOB。

 

这也是为什么大表都单独定义收集统计信息的原因,面试过很多的同学,基本上说出直接原因的没有多少,都说是照着网上这么做的。

 

 

这里也可以看到相关的10053事件中的成本信息,具体可以参考以下的地址了解每个类型的含义。

 


最终我们在业务维护时间创建了cn+c_date联合索引后的执行计划,至今再无类似的SQL性能问题。

 


时间: 2024-07-29 16:02:53

管好统计信息,开启SQL优化之门的相关文章

收集统计信息的SQL脚本(sosi.sql)--崔华大师

收集统计信息的SQL脚本(sosi.sql)--崔华大师 点击(此处)折叠或打开 set echo off set scan on set lines 150 set pages 66 set verify off set feedback off set termout off column uservar new_value Table_Owner noprint select user uservar from dual; set termout on column TABLE_NAME

MySQL · 性能优化· CloudDBA SQL优化建议之统计信息获取

阿里云CloudDBA具有SQL优化建议功能,包括SQL重写建议和索引建议.SQL索引建议是帮助数据库优化器创造最佳执行路径,需要遵循数据库优化器的一系列规则来实现.CloudDBA需要首先计算表统计信息,是因为: 数据库优化器通常是基于代价寻找执行路径: SQL优化建议所针对的数据库不限于MySQL数据库,也不局限于某一个特定版本: 1. 基本原则 数据库统计信息在SQL优化起到重要作用.用来估算查询条件选择度的常见统计信息包括表统计信息和字段统计信息.DBA计算查询条件选择度或代价时经常通过

SQL Server幕后英雄 - 统计信息

SQL Server查询优化器对于执行计划成本的评估是基于数据库统计信息的.所以,数据库统计信息直接影响到数据库查询效率,是数据库系统快速响应,低延迟特性的幕后英雄,但是我们又经常忽视数据库统计信息的存在和维护,怀着为英雄正名和唤醒大家对幕后英雄尊重的目的写作这篇文章. 什么是统计信息 SQL Server查询优化器使用统计信息来评估表或索引视图的一个或多个列中值的分布,这个分布信息提供了用于创建高质量的执行计划的基础(称为基数).更为通俗一点说,SQL Server的执行计划是基于统计信息来评

MS SQL统计信息浅析下篇

   MS SQL统计信息浅析上篇对SQL SERVER 数据库统计信息做了一个整体的介绍,随着我对数据库统计信息的不断认识.理解,于是有了MS SQL统计信息浅析下篇. 下面是我对SQL Server统计信息的一些探讨或认识,如有不对的地方,希望大家能够指正. 触发统计信息更新条件疑问     关于这个触发统计信息更新的条件.因为我在很多资料上看到过,例如Microsoft  SQL Server 企业级平台管理实践. 我自己上篇也是这样解释的.    1:普通表上,触发数据库自动更新统计信息

MS SQL 统计信息浅析上篇

统计信息概念     统计信息是一些对象,这些对象包含在表或索引视图中一列或多列中的数据分布有关的统计信息.数据库查询优化器使用这些统计信息来估计查询结果中的基数或行 数. 通过这些基数估计,查询优化器可以生成高质量的执行计划. 例如,查询优化器可以使用基数估计选择索引查找运算符而不是耗费更多资源的索引扫描运算符,从而提高查询性能.[参考MSDN]     其实如果你以前没有接触过统计信息,你可以将其看做是数据库为了得到最优的执行计划,统计数据库里面表.索引等对象的一些数据,例如表的记录数.所有

SQL Server · 特性介绍 · 统计信息

SQL Server查询优化器对于执行计划成本的评估是基于数据库统计信息的.所以,数据库统计信息直接影响到数据库查询效率,是数据库系统快速响应,低延迟特性的幕后英雄,但是我们又经常忽视数据库统计信息的存在和维护,怀着为英雄正名和唤醒大家对幕后英雄尊重的目的写作这篇文章. 什么是统计信息 SQL Server查询优化器使用统计信息来评估表或索引视图的一个或多个列中值的分布,这个分布信息提供了用于创建高质量的执行计划的基础(称为基数).更为通俗一点说,SQL Server的执行计划是基于统计信息来评

在DB2优化器中使用分布统计信息

本文配套源码 简介 为了执行查询或 DML 语句(INSERT.UPDATE.DELETE),DB2 必须创建一个访问计划(access plan).访问计划定义按什么顺序访问表,使用哪些索引,以及用何种连接(join)方法来关联数据.好的访问计划对于 SQL 语句的快速执行至关重要.DB2 优化器可以创建访问计划.这是一种基于成本的优化器,这意味着它是根据表和索引的相关统计信息来作出决策的.DB2 在生成统计信息时,不但能提供基本统计信息,还允许创建所谓的分布统计信息.不但数据库管理员要理解分

ORACLE SQL调优之统计信息缺失导致的逻辑读暴增

    2016年11月8日,接到广西负责人申告,说决策系统一条SQL平时执行2s左右能执行完,现在却要执行2:30多才能出结果,请求对其做处理.     操作系统:RHEL LINUX 6.4     数据库版本:11.2.0.4     首先,登录服务器查看数据库服务器的状态: [oracle@orcl ~]$ free -m              total       used       free     shared    buffers     cached Mem:    

Oracle 判断 并 手动收集 统计信息 脚本

CREATE OR REPLACE PROCEDURE SchameB.PRC_GATHER_STATS AUTHID CURRENT_USER IS BEGIN SYS.DBMS_STATS.GATHER_TABLE_STATS('SchName', 'TableName', CASCADE => TRUE); END; /   select owner,table_name,last_analyzed,num_rows from dba_tables where owner='SYSTEM'