如何在不改SQL的情况下优化数据库
主题简介
在数据库运维中我们会遇到各种各样的问题,这些问题的根源可能很明显,也可能被某种表象掩盖而使我们认不清。所以运维面临的两大问题就是,第一我们没有看清本质,第二应用不允许修改。那么我们如何解决这两个问题,是每一个运维者都应该思考的。今晚的分享将会从三个方面来进行。如何准确定位问题,如何不修改应用进行优化,以及如何通过SQL审核防患未然。
大家好。我是云和恩墨公司的专家罗海雄,主要专长于性能优化这个领域,包括数据库的优化,SQL优化等。今天给大家分享的主题是“如何在无法修改应用时进行数据库优化”。
我先从一个真实的案例说起。我们的一个客户,是一个汽车经销商,他们的财务系统出现了严重的性能问题。
这是他们的CPU压力的示意图。
红色的是CPU使用量,绿色的是CPU空闲,黑色的是IO等待。我们可以看到,在图的中间部分,也就是月底的时候,CPU使用量已经达到80-90%, 而CPU Idle 已经接近0了。
中间似乎还有一段CPU 空闲100%, 其实是由于数据库压力太大,主机自动重启了。 这种情况已经严重影响他们公司财务系统的月结工作。他们赶紧找到我们公司,我一看AWR, 发现大量SQL执行时间很长。
从表里可以看到,第一个SQL平均一次执行需要2700秒,后面还有几个SQL单次执行在2000秒以上,显然有很大问题。
发现明显有部分SQL写法上存在问题,正是这些SQL,导致数据库压力过大。
其中一条SQL是这个样子的:
几个表都是几千万条记录的大表,re.FSrcEntryId是个选择都很高的栏位,sie.FID是个主键, si.FId 也是主键。T_IM_SaleIssueEntry是外连接的驱动表,但是上面没有直接的条件。T_IM_SaleIssueBill 和 T_BOT_RELATIONENTRY都是被驱动表,上面有两个条件:
si.FTransactionTypeIDIN (:3, :4)和re.FSrcEntryId IN (:5, :6)
这种情况下,由于被驱动表已经有了确定值,逻辑上来说,外连接和内连接是等价的,但是Oracle 10g 的优化器没有为这种情况做优化,导致在优化前,走了大表的全表扫描。
这一类SQL不少。我们最早的建议就是修改部分写法存在问题的SQL, 从源头入手,尝试解决。比如说,把LEFT OUTER JOIN 改成普通JOIN, 逻辑上是一样的,就能走刚才的好的执行计划。
但是,应用开发厂商表示,由于这个版本比较老,他们已经没有专门的人员对代码进行维护,无法修改SQL。
这就是作为一个系统维护DBA,经常会碰到的问题。系统刚上线,一切很美好... 一两年后,由于数据量的积累,用户数增多,功能点使用增多等原因,会使负荷逐渐增加,从而出现性能问题。根据我们的经验,在这些性能问题里面,SQL的问题可能占了80%.但是,由于种种原因,可能就是没法修改SQL.
比如说:
-- 使用封装好的商业套件
-- 外包开发,开发商已经离场
-- 自行开发,但开放部门不愿意配合进行代码修改
这就到了今天的主题:“如何在无法修改应用时进行数据库优化”
总的来说,可以从硬件和软件两个方面去解决:硬件方面,可以通过增加或者CPU,增加内存,做一定的改善。也可以通过升级成增加RAC, 也可以增加CPU的处理能力。存储方面,升级更好地存储,针对一些I/O要求比较高的系统,也一种优化的手段。
这是我们的一个客户,通过把存储介质升级到PCIE Flash卡,极大的改善了I/O性能问题,是整个系统的性能得到了极大的提升。
我们公司的zData产品,通过高速的PCIE Flash卡,结合超大带宽,超小延迟的高速IB网络, 也可以非常有效地提高I/O的性能,总体性能是传统存储的10倍以上。这样,在不修改任何SQL的情况下,就轻松解决了I/O的瓶颈,提高的系统的性能。当然,对于不差钱的单位/企业,使用Oracle的Exadata也是一种方法;很简便的、不修改应用就能明显提高系统性能的方法。动硬件往往涉及到预算。不增加开销的情况下,也可以通过数据库的层面做一些优化。
回到我一开始介绍的那个案例。
经过研究,我们发现,LEFT OUTER JOIN不能等价转换成普通JOIN是Oracle 10g的行为模式。在Oracle 11g中,优化器做了升级,能够识别并内部进行这种转换。而恰巧,用户用的是Oracle 11g的数据库,只是由于应用开发方的要求,把优化器模式设为了10.2.0.1.
最终,通过和应用开发方,使用方的多次沟通和测试,最终把优化器模式设为了11.2.0, 从而解决了最大的问题。
当然,LEFT OUTER JOIN只是其中一个问题,后来,在这个客户的数据库上,我们还有针对性的建立了100多个索引。最终,在没有修改任何SQL的情况下,彻底解决了用户的系统性能问题。
通常来说,数据库层面的优化包括
参数调整:内存参数,优化器参数等
表结构调整:索引, 并行度,分区
SQL执行计划调整:SQL Profile,SPM,SQL Patch
其它: Cache 表、统计信息、物化视图+查询重写、数据归档等等
合适的优化器参数,会使你系统索引的问题看起来很简单,但往往是最有效的方法之一。大家讨论的比较多,我就不深入了。分区以及数据归档也是一个常用的手段。实际上,数据都是有生命周期的。很多用户的数据库里面,存了很多已经不需要的数据,通过清理、归档这些数据,往往也能获得比较高的优化效果。
还有一些情况,SQL写的并没有问题,但由于种种原因,数据库经常走错执行计划;这时候,通过改写SQL, 增加Hint是一种常见解决方式。在无法修改SQL的情况下,也可以通过一些手段对SQL执行计划进行固定。
这些手段主要包括有:
SQL Profile(Oracle 10g以后)
SQL Plan Baseline Management(Oracle 11g以后)
SQL Patch
Outline
SQL profile在Oracle 10g引入:
通过为特定的SQL文本指定优化器的一些信息,从而引导优化器生成更为合理的SQL执行计划。达到不修改SQL文本就可以改变并指定执行计划的目的。
SQL-Profile 主要通过dbms_sqltune包进行控制。时间关系,今天就不为大家演示了。
SQL Plan Management在Oracle 11g引入:
通过为特定的SQL指定已知SQL执行计划,强制优化器选择已经指定的SQL执行计划,从而达到不修改SQL文本即可修改执行计划的目的。
可以指定多个可用执行计划供优化器选择。
可以和SQL Tuning Advisor一起用
可以自动收集运行库中SQL 作为已知执行计划。
也可以手工设置。
SQL Plan Management主要通过DBMS_SPM包进行控制,SQL Patch是一种强行给SQL加Hint的方法,主要通过sys.dbms_sqldiag_internal.i_create_patch进行。
不同的数据库优化方式对整个数据库影响面各有不同,在使用的时候,需要谨慎的程度也不一样。
经典问题分享
问题一
关于SQL Profile使用方法有什么好的推荐的书籍或者文档介绍之类的
关于 SQL profile,推荐老熊的两篇文章
http://www.laoxiong.net/sql-profiles-part.html
http://www.laoxiong.net/sql-profiles-partii.html
问题二
关于驱动表和被驱动表如何确定?
对于Nested loop来说,被驱动表需要有高选择度索引,驱动表的结果应该尽量小。 Hash Join没有被驱动表需要索引的问题,只剩下驱动表结果集小的需求。多数情况,能够迅速帮你把数据量减下来的表,适合当驱动表。
问题三
同一条sql的执行计划经常会变是什么问题?
统计信息以及绑定变量是变化的主因
Oracle的新特性 基数反馈和adaptive cursor 也会造成执行计划不稳定
问题四
咨询一下zdata分布式存储采用的是什么raid方式?
zdata分布式存储采用的是分散的mirror机制。每个块至少在两个主机的Flash上存放,同时有机制保证某个主机出现问题后,把相应的块重新分布到其他主机上。
问题五
很多文章都在说索引高度太大会增加io开销,在数据量日渐增多的情况下,如何降低索引高度呢?
分区是一个办法
不是特别建议通过重建的方法强行降blevel, 在反弹的时候容易造成索引分裂,影响系统性能
问题六
今天我们优化sql上午时候,表关联,使用了jion,每个表都走了索引,但是从执行计划上看消耗掉的cpu还是很多,没有明显的下降。想问一下。优化sql需要考虑到具体方面
虽然走索引,当时如果驱动表结果集较大,多次的索引扫描,同样会导致性能不好。
总的来说,访问越少的Block, 性能就越好。合适的条件尽可能放在执行计划链的前段,迅速把结果集圈定在最终需要的结果集里。
如果缺乏合适的过滤条件,那么,考虑用Hash Join代替nested loop. 当然,还得看实际的情况。
问题七
动态生成的sql如何进行优化
“动态生成的sql如何优化”这个问题有点宽泛。我猜测提问者想问的可能根据用户输入条件动态拼接而成的SQL如何优化。这个问题得具体分析。通常来说,尽量把条件限制在第一个表,适当的多建索引,以及针对用户实际行为进行针对性优化。
比如说,在我服务过的一个公司,系统里有个界面,操作人员可以根据需要选择不同的条件,这些条件组合来自于多个表。
后来,我们直接分析系统访问日志,发现80%的查询都是特定两个表的条件,分别位于from 列表的第一个和第三个表。而第二个表是个关系表。
于是,我采用了比较少见的处理方式,把第一个表和第三个表的关键字段组合起来,创建了一个新的表,并在这个表的相应字段创建索引,而这个表的数据通过trigger的方式进行同步。最终,相关的SQL性能提升数百倍,从30秒钟下降到100ms。系统总体CPU降低 50%以上。
问题八
什么时候数据库会走错误的执行计划啊?
Oracle的新特性 基数反馈和adaptive cursor 也会造成执行计划不稳定
问题九
trigger能保证事务吗?
可以
讲师PPT分享:
链接: https://pan.baidu.com/s/1eRKuCAQ 密码: kf3t
如何在不改SQL的情况下优化数据库的更多相关文章
- m_Orchestrate learning system---二十九、什么情况下用数据库做配置字段,什么情况下用配置文件做配置
m_Orchestrate learning system---二十九.什么情况下用数据库做配置字段,什么情况下用配置文件做配置 一.总结 一句话总结: 配置文件 开发人员 重置 数据库 非开发人员 ...
- Sql Server优化之索引提示----我们为什么需要查询提示,Sql Server默认情况下优化策略选择的不足
环境: Sql Server2012 SP3企业版,Windows Server2008 标准版 问题由来: 最近在做DB优化的时候,发现一个存储过程有非常严重的性能问题, 由于整个SP整体逻辑是一个 ...
- 使用阿里云RDS for SQL Server性能洞察优化数据库负载-初识性能洞察
简介 数据库性能调优通常需要较高数据库水平,并伴随较多的前期准备工作,比如收集各种性能基线.不同种类的性能指标.慢SQL日志等,这通常费时费力且效果一般,当面对多个数据库时总体拥有成本会大幅增加.今天 ...
- 利用Xtrabackup在不停机的情况下备用数据库迁移
什么是Xtrabackup?答:Xtrabackup是一个对InnoDB做数据备份的工具,支持在线热备份(备份时不影响数据读写),是商业备份工具InnoDB Hotbackup的一个很好的替代品. 下 ...
- 总结Oracle8i 的UNDO表空间损坏(ORA-01092及ORA-00600【4193】)情况下的数据库不完全恢复的经历
服务器断电重启导致备份生产环境的恢复目录库无法进行启动,提示Ora-01092例程终止.强行断开连接 查看跟踪日志: Wed Jan 10 08:41:37 2018 Errors in file d ...
- SQL Server 紧急状态下的数据库恢复
背景:由于服务器硬盘损坏,服务器异常关机.重新进入后,数据库为质疑状态.(数据库名字上面有个感叹号,连接不了) 经过无数次的百度以及大佬们的指点下,终于成功恢复,下面来说一下方法. 第一种: 1.在服 ...
- SQL点滴22—性能优化没有那么神秘
原文:SQL点滴22-性能优化没有那么神秘 经常听说SQL Server最难的部分是性能优化,不禁让人感到优化这个工作很神秘,这种事情只有高手才能做.很早的时候我在网上看到一位高手写的博客,介绍了SQ ...
- MySQL优化篇(一),我可以和面试官多聊几句吗?——SQL优化流程与优化数据库对象
我可以和面试官多聊几句吗?只是想偷点技能过来.MySQL优化篇(基于MySQL8.0测试验证),上部分:优化SQL语句.数据库对象,MyISAM表锁和InnoDB锁问题. MyISAM表锁和InnoD ...
- SQL Server 2008 R2 下移动数据库的存储位置
使用场景:1. 该数据库增长的较大,存储磁盘空间不足: 2. 在特定情况下该数据库需要移动到另外一块磁盘上(呵呵...我的情况就是之前的磁盘要还给别人) 步骤: 1. 新建查询 SELECT na ...
随机推荐
- 优矿众包对冲基金计划”优选策略---100w实盘资金管理权!!
https://uqer.io/contest/ http://www.cnblogs.com/dunitian/p/4939369.html 优连
- Android获取屏幕高度、标题高度、状态栏高度详解
Android获取屏幕高度的方法主要由view提供 通过View提供的方法获取高度方式有两种: 1, 当前显示的view中直接获取当前view高宽2,通过Activity的getWindow().fi ...
- Unity教程之-基于行为树与状态机的游戏AI
AI.我们的第一印象可能是机器人,现在主要说在游戏中的应用.关于AI的相关文章我们在前面也提到过,详细请戳这现代的计算机游戏中已经大量融入了AI元素,平时我们进行游戏时产生的交互都是由AI来完成的.比 ...
- ChemDraw教程之怎么连接ChemDraw结构
将两个独立的ChemDraw结构连接到一起是使用者学习操作ChemDraw绘制窗口内容的基本能力之一.为了进一步了解ChemDraw软件,本教程将具体为您介绍怎么连接ChemDraw结构. 一.化学结 ...
- linux 安装 nodejs
原文地址:https://nodejs.org/en/download/package-manager/#enterprise-linux-and-fedora 1)定位到nodejs的官方源(如果直 ...
- shell基础(八)-循环语句
国庆过后:感觉有点慵懒些了:接着上篇:我们继续来学习循环语句. 一. for循环 与其他编程语言类似,Shell支持for循环. for循环一般格式为: for 变量 in 列表 do command ...
- stl中的map经验
如果想使用一个map临时变量装载参数map,不需要使用new创建一个对象. 声明一个变量,直接赋值就可以.map内部自己重载了=操作符,会自己分配内存.
- JavaScript的记忆函数真的可以提升性能吗?
1 记忆函数是什么呢? 让函数记住曾经计算过的参数对应的结果 2 那我们为什么使用记忆函数呢? 答案是 避免重复计算 3 在工作中如何使用和实现函数记忆 ? 形成闭包,在闭包中维护一个哈希数组(其 ...
- Linux 启动文件、设置环境变量的位置
系统级启动文件 ==================================== 1./etc/rc 主启动文件,不要修改它 2./etc/rc.conf 决定启动哪些系统自带的守护进程 ...
- 深入浅出Docker(三):Docker开源之路
背景 Docker从一开始的概念阶段就致力于使用开源驱动的方式来发展,它的成功缘于国外成熟的开源文化氛围,以及可借鉴的社区运营经验.通过本文详细的介绍,让大家可以全面了解一个项目亦或者一项技术是如何通 ...