知识大全 关于数据库优化问题收集汇总

Posted 索引

篇首语:日日行,不怕千万里;常常做,不怕千万事。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 关于数据库优化问题收集汇总相关的知识,希望对你有一定的参考价值。

笔者在工作实践中发现 不良的SQL往往来自于不恰当的索引设计 不充份的连接条件和不可优化的where子句 以下就对数据库优化问题进行了介绍 需要的朋友可以参考下   在对它们进行适当的优化后 其运行速度有了明显地提高! 下面将从这三个方面分别进行总结 为了更直观地说明问题 所有实例中的SQL运行时间均经过测试 不超过1秒的均表示为(< 秒) 测试环境: 主机 HP LH II  主频 MHZ  内存 兆 操作系统 Operserver 数据库 Sybase   一 不合理的索引设计 例 表record有 行 试看在不同的索引下 下面几个 SQL的运行情况 在date上建有一非个群集索引 select count(*) from record where date > and date < and amount > ( 秒) select date sum(amount) from record group by date( 秒) select count(*) from record where date > and place in ( BJ SH ) ( 秒)  分析 date上有大量的重复值 在非群集索引下 数据在物理上随机存放在数据页上 在范围查找时 必须执行一次表扫描才能找到这一范围内的全部行 在date上的一个群集索引 select count(*) from record where date > and date < and amount >  ( 秒) select date sum(amount) from record group by date( 秒) select count(*) from record where date > and place in ( BJ SH )( 秒)  分析  在群集索引下 数据在物理上按顺序在数据页上 重复值也排列在一起 因而在范围查找时 可以先找到这个范围的起末点 且只在这个范围内扫描数据页 避免了大范围扫描 提高了查询速度 在place date amount上的组合索引 select count(*) from record where date > and date < and amount >  ( 秒) select date sum(amount) from record group by date( 秒) select count(*) from record where date > and place in ( BJ SH )(< 秒)  分析  这是一个不很合理的组合索引 因为它的前导列是place 第一和第二条SQL没有引用place 因此也没有利用上索引 第三个SQL使用了place 且引用的所有列都包含在组合索引中 形成了索引覆蓋 所以它的速度是非常快的 在date place amount上的组合索引 select count(*) from record where date > and date < and amount > (< 秒) select date sum(amount) from record group by date( 秒) select count(*) from record where date > and place in ( BJ SH )(< 秒)  分析  这是一个合理的组合索引 它将date作为前导列 使每个SQL都可以利用索引 并且在第一和第三个SQL中形成了索引覆蓋 因而性能达到了最优 总结 缺省情况下建立的索引是非群集索引 但有时它并不是最佳的 合理的索引设计要建立在对各种查询的分析和预测上 一般来说 ① 有大量重复值 且经常有范围查询(beeen > <  >= < =)和order by group by发生的列 可考虑建立群集索引 ② 经常同时存取多列 且每列都含有重复值可考虑建立组合索引 ③ 组合索引要尽量使关键查询形成索引覆蓋 其前导列一定是使用最频繁的列   二 不充份的连接条件 例 表card有 行 在card_no上有一个非聚集索引 表account有 行 在account_no上有一个非聚集索引 试看在不同的表连接条件下 两个SQL的执行情况 select sum(a amount) from account a card b where a card_no = b card_no( 秒) select sum(a amount) from account a card b where a card_no = b card_no and a account_no=b account_no(< 秒)  分析  在第一个连接条件下 最佳查询方案是将account作外层表 card作内层表 利用card上的索引 其I/O次数可由以下公式估算为 外层表account上的 页+(外层表account的 行*内层表card上对应外层表第一行所要查找的 页)= 次I/O 在第二个连接条件下 最佳查询方案是将card作外层表 account作内层表 利用account上的索引 其I/O次数可由以下公式估算为 外层表card上的 页+(外层表card的 行*内层表account上对应外层表每一行所要查找的 页)= 次I/O 可见 只有充份的连接条件 真正的最佳方案才会被执行 总结 多表操作在被实际执行前 查询优化器会根据连接条件 列出几组可能的连接方案并从中找出系统开销最小的最佳方案 连接条件要充份考虑带有索引的表 行数多的表 内外表的选择可由公式 外层表中的匹配行数*内层表中每一次查找的次数确定 乘积最小为最佳方案 查看执行方案的方法  用set showplanon 打开showplan选项 就可以看到连接顺序 使用何种索引的信息 想看更详细的信息 需用sa角色执行dbcc( )   三 不可优化的where子句 例 下列SQL条件语句中的列都建有恰当的索引 但执行速度却非常慢 select * from record wheresubstring(card_no )= ( 秒) select * from record whereamount/ < ( 秒) select * from record whereconvert(char( ) date )= ( 秒) 分析 where子句中对列的任何操作结果都是在SQL运行时逐列计算得到的 因此它不得不进行表搜索 而没有使用该列上面的索引 如果这些结果在查询编译时就能得到 那么就可以被SQL优化器优化 使用索引 避免表搜索 因此将SQL重写成下面这样 select * from record where card_no like % (< 秒) select * from record where amount< * (< 秒) select * from record where date= / / (< 秒) 你会发现SQL明显快起来! 例 表stuff有 行 id_no上有非群集索引 请看下面这个SQL select count(*) from stuff where id_no in( )( 秒) 分析 where条件中的 in 在逻辑上相当于 or 所以语法分析器会将in ( )转化为id_no = or id_no= 来执行 我们期望它会根据每个or子句分别查找 再将结果相加 这样可以利用id_no上的索引 但实际上(根据showplan) 它却采用了"OR策略" 即先取出满足每个or子句的行 存入临时数据库的工作表中 再建立唯一索引以去掉重复行 最后从这个临时表中计算结果 因此 实际过程没有利用id_no上索引 并且完成时间还要受tempdb数据库性能的影响 实践证明 表的行数越多 工作表的性能就越差 当stuff有 行时 执行时间竟达到 秒!还不如将or子句分开 select count(*) from stuff where id_no= select count(*) from stuff where id_no= 得到两个结果 再作一次加法合算 因为每句都使用了索引 执行时间只有 秒 在 行下 时间也只有 秒 或者 用更好的方法 写一个简单的存储过程 create proc count_stuff asdeclare @a intdeclare @b intdeclare @c intdeclare @d char( )beginselect @a=count(*) from stuff where id_no= select @b=count(*) from stuff where id_no= endselect @c=@a+@bselect @d=convert(char( ) @c)print @d 直接算出结果 执行时间同上面一样快!    总结   可见 所谓优化即where子句利用了索引 不可优化即发生了表扫描或额外开销 任何对列的操作都将导致表扫描 它包括数据库函数 计算表达式等等 查询时要尽可能将操作移至等号右边 in or子句常会使用工作表 使索引失效 如果不产生大量重复值 可以考虑把子句拆开 拆开的子句中应该包含索引 要善于使用存储过程 它使SQL变得更加灵活和高效 从以上这些例子可以看出 SQL优化的实质就是在结果正确的前提下 用优化器可以识别的语句 充份利用索引 减少表扫描的I/O次数 尽量避免表搜索的发生 其实SQL的性能优化是一个复杂的过程 上述这些只是在应用层次的一种体现 深入研究还会涉及数据库层的资源配置 网络层的流量控制以及操作系统层的总体设计   开发人员如果用到其他库的Table或View 务必在当前库中建立View来实现跨库操作 最好不要直接使用“databse dbo table_name” 因为sp_depends不能显示出该SP所使用的跨库table或view 不方便校验 开发人员在提交SP前 必须已经使用set showplan on分析过查询计划 做过自身的查询优化检查 高程序运行效率 优化应用程序 在SP编写过程中应该注意以下几点 a) SQL的使用规范 i 尽量避免大事务操作 慎用holdlock子句 提高系统并发能力 ii 尽量避免反复访问同一张或几张表 尤其是数据量较大的表 可以考虑先根据条件提取数据到临时表中 然后再做连接 iii 尽量避免使用游标 因为游标的效率较差 如果游标操作的数据超过 万行 那么就应该改写 如果使用了游标 就要尽量避免在游标循环中再进行表连接的操作 iv 注意where字句写法 必须考虑语句顺序 应该根据索引顺序 范围大小来确定条件子句的前后顺序 尽可能的让字段顺序与索引顺序相一致 范围从大到小 v 不要在where子句中的“=”左边进行函数 算术运算或其他表达式运算 否则系统将可能无法正确使用索引 vi 尽量使用exists代替select count( )来判断是否存在记录 count函数只有在统计表中所有行数时使用 而且count( )比count(*)更有效率 vii 尽量使用“>=” 不要使用“>” viii 注意一些or子句和union子句之间的替换 ix 注意表之间连接的数据类型 避免不同类型数据之间的连接 x 注意存储过程中参数和数据类型的关系 xi 注意insert update操作的数据量 防止与其他应用冲突 如果数据量超过 个数据页面( k) 那么系统将会进行锁升级 页级锁会升级成表级锁 b) 索引的使用规范 i 索引的创建要与应用结合考虑 建议大的OLTP表不要超过 个索引 ii 尽可能的使用索引字段作为查询条件 尤其是聚簇索引 必要时可以通过index index_name来强制指定索引 iii 避免对大表查询时进行table scan 必要时考虑新建索引 iv 在使用索引字段作为条件时 如果该索引是联合索引 那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引 否则该索引将不会被使用 v 要注意索引的维护 周期性重建索引 重新编译存储过程 c) tempdb的使用规范 i 尽量避免使用distinct order by group by having join ***pute 因为这些语句会加重tempdb的负担 ii 避免频繁创建和删除临时表 减少系统表资源的消耗 iii 在新建临时表时 如果一次性插入数据量很大 那么可以使用select into代替create table 避免log 提高速度 如果数据量不大 为了缓和系统表的资源 建议先create table 然后insert iv 如果临时表的数据量较大 需要建立索引 那么应该将创建临时表和建立索引的过程放在单独一个子存储过程中 这样才能保证系统能够很好的使用到该临时表的索引 v 如果使用到了临时表 在存储过程的最后务必将所有的临时表显式删除 先truncate table 然后drop table 这样可以避免系统表的较长时间锁定 vi 慎用大的临时表与其他大表的连接查询和修改 减低系统表负担 因为这种操作会在一条语句中多次使用tempdb的系统表 d) 合理的算法使用   根据上面已提到的SQL优化技术和ASE Tuning手册中的SQL优化内容 结合实际应用 采用多种算法进行比较 以获得消耗资源最少 效率最高的方法 具体可用ASE调优命令 set statistics io on set statistics time on set showplan on 等 cha138/Article/program/MySQL/201311/29522

相关参考

知识大全 .net基础收集汇总

最近的面试让我知道基础知识的重要性而我也每天都在网上找一些基础题来看其实面试无非都是一些理论基础只有基础过关了才会被问到技术性的问题所以第一关一定要打好   下面是我收集的一些题目以及答案(

知识大全 关于SQL Server事务日志的问题汇总

关于SQLServer事务日志的问题汇总  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  用BAC

小城镇污水处理十项关键技术汇总和案例分析

由于污水排放面广而分散,且规模较小,所以小城镇一般不宜采用传统的城市污水收集,需要结合地形地貌,因地制宜地解决小城镇污水收集问题。类似于城市污水收集的集中式管网模式往往适用于地势平缓,排水相对集中的小

小城镇污水处理十项关键技术汇总和案例分析

由于污水排放面广而分散,且规模较小,所以小城镇一般不宜采用传统的城市污水收集,需要结合地形地貌,因地制宜地解决小城镇污水收集问题。类似于城市污水收集的集中式管网模式往往适用于地势平缓,排水相对集中的小

小城镇污水处理十项关键技术汇总和案例分析

由于污水排放面广而分散,且规模较小,所以小城镇一般不宜采用传统的城市污水收集,需要结合地形地貌,因地制宜地解决小城镇污水收集问题。类似于城市污水收集的集中式管网模式往往适用于地势平缓,排水相对集中的小

知识大全 Oracle语句优化规则汇总(9)

Oracle语句优化规则汇总(9)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!使用提示(Hint

知识大全 Oracle语句优化规则汇总(5)

Oracle语句优化规则汇总(5)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!   O

知识大全 Oracle语句优化规则汇总(10)

Oracle语句优化规则汇总(10)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!需要当心的WHE

知识大全 Oracle语句优化规则汇总(6)

Oracle语句优化规则汇总(6)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!基础表的选择  基

知识大全 数据库规范化与优化问题讲解

  数据库设计是应用程序设计的基础其性能直接影响应用程序的性能数据库性能包括存储空间需求量的大小和查询响应时间的长短两个方面为了优化数据库性能需要对数据库中的表进行规范化规范化的范式可分为第一范式第二