㈠ 数据库的表如果没有主键查询速度会慢吗
我们搭建一个 Mysql 5.7 的环境,此处省略搭建步骤。
写个简单的脚本,制造一批带主键和不带主键的表:
可以看到执行时间变成了 0.67s。
整理
我们诊断的关键点如下:
1. 对于 information_schema 中的元数据表,执行计划不能提供有效信息。
2. 通过查看 MySQL 改写后的 SQL,我们猜测了优化器发生了误判。
3. 我们增加了 hint,指导 MySQL 正确进行优化判断。
但目前我们的实验仅限于猜测,猜中了万事大吉,猜不中就无法做出好的诊断。
㈡ 如何提高sql语句的执行效率
1、使用ordered提示
Oracle必须花费大量的时间来剖析多表的合并,用以确定表合并的最佳顺序。SQL表达式涉及七个乃至更多的表合并,那么有时就会需要超过30分钟的时间来剖析,Ordered这个提示(hint)和其他的提示一起使用能够产生合适的合并顺序。
2、使用ordered_predicates
ordered_predicates提示在查询的WHERE子句里指定的,并被用来指定布尔判断(Booleanpredicate)被评估的顺序。在没有ordered_predicates的情况下,Oracle会使用下面这些步骤来评估SQL判断的顺序:子查询的评估先于外层WHERE子句里的Boolean条件。
所有没有内置函数或者子查询的布尔条件都按照其在WHERE子句里相反的顺序进行评估,即最后一条判断最先被评估。每个判断都带有内置函数的布尔判断都依据其预计的评估值按递增排列。
3、限制表格合并评估的数量
提高SQL剖析性能的最后一种方法是强制取代Oracle的一个参数,这个参数控制着在评估一个查询的时候,基于消耗的优化器所评估的可能合并数量。
(2)数据库hint扩展阅读:
1、表设计的优化,数据行的长度不要超过8020字节,如果超过这个长度的话在物理页中这条数据会占用两行从而造成存储碎片,降低查询效率。
2、语句的查询优化,保证在实现功能的基础上,尽量减少对数据库的访问次数;
3、建立高效的索引创建索引一般有以下两个目的:维护被索引列的唯一性和提供快速访问表中数据的策略。
大型数据库有两种索引即簇索引和非簇索引,一个没有簇索引的表是按堆结构存储数据,所有的数据均添加在表的尾部,而建立了簇索引的表,其数据在物理上会按照簇索引键的顺序存储。个表只允许有一个簇索引。
4、强制查询转换,有时候oracle 的优化器未必能走正确的查询路线,这个时候就需要添加一些hint 之类的来规定他的执行路线。当然了,这个未必是最好的处理方案。因为虽然现在走这个路线是对的,以为因为数据的变化到这这个HINT 变得不可取。
㈢ oracle 的hint有什么用
相对而言ORACLE优化器已经非常智能,产生的执行计划也是最优的,但是ORACLE还是提供了一些hint供用户显示的控制执行计划,因为大千世界各种各样的业务都有,ORACLE优化器生成的执行计划并不一定适用于所有业务,同时hint对于DBA而言更是一件利器,我们可以通过hint看到优化后的执行计划,总结一下常用hint。1.全表扫描hintfull(table_name)相对而言,全表扫描hint使用场合较少,但是要知道,全表扫描并不一定比索引效率低,特别是查询表中80%以上的数据库,全表扫描的效率要高于索引扫描。2.索引hintindex(table_nameindex_name)这两种hint一个是强制使用索引,另一个是强制执行计划不要走索引,什么用呢?常用于SQL调优过程中对比索引和非索引扫描。3.索引快速扫描hintindex_ffs(table_nameindex_name)这种索引称之为索引快速扫描,常用于统计索引列键值的个数,如count(object_id),跟全表扫描很像,但效率要比全表扫描要高很多,也就是执行计划中看到的FASTFULLSCN。4.索引跳跃扫描hintindex_ss(table_nameindex_name)该hint在执行计划中就是传说中的INDEXSKIPSCAN这个对新手而言不太好理解,举个例子索引有两个列(A,B)类型组合索引,但是查询中where条件只有B没有Aselect*fromwhereb=1,此时ORACLE优化器走的索引就是所谓的索引跳跃扫描,只在CBO下适用,在RBO不适用。5.表关联hintuser_nl(table_name1table_name2)此hint是表之间关联效率最高的一种,通常用于一大一小两表之间进行关联查询,小表作驱动表进行全表扫描,大表上要求有索引,走索引扫描,代价最低。6.表关联hintuse_hash(table_name1table_name2)如果两个表一大一小,但是大表没有索引就会选择HASH,如果两个结果集比较小还可以承受,但是如果两个较大的表HASH的话,会直接将数据库HANG住,最好避免这种算法7.表关联hintuser_merge(table_name1table_name2)两个表进行关联,分别对全个表进行全表扫描后排序然后进行合并,排序既消耗内存又消耗CPU,总之代价比较大,常通过在两个表上创建索引避免此类连接的发生。因此对比后发现,只有nested_loop方式进行关联是最优的。8.表顺序hintleading(table_name1table_name2)在RBO模式下,我们常常通过考虑from后面表的先后顺序来进行SQL优化,但是此方法对RBO模式不再适用,CBO模式下按照顺序选择驱动表9.数据加载hintappend()直接路径加载,对于大表操作极为有用,原理是什么呢?打个比方,好比两个超市理货员,一人一箱货需要上架到货架上,一个人去找货架中空闲位置去放,可能需要找N个空闲位,另一个人找一个空的货架直接放上去,那个效果最高?当然是第二个,此hint的作用就是让ORACLE找一个大空亲块直接存放新数据,而不是挤空闲位置去放新数据,如果此hint同时加上nologing联合使用效果更高,常用于数据迁移项目中。10.dblink处理端hintdriving_site(table_name)此hint常用于通过dblink连接处理数据的业务,它的作用是将本地表推送到远端数据库进行关联然后将结果返回,常用于本地表较小,远端表较大的情况,效果很是不错。11.数据返回模式hintfirst_rows该hint是影响数据返回模式hint,添加后ORACLE将边处理边返回,数据仓库中用的比较多,但是在OLTP系统中也常见,上次系统优化就因为一兄弟在添加hint时,添加后发现执行计划没变,于是将原有的hintfirst_rows然后添加hintdriving_site(),执行计划是变了,变化是因去去掉first_rows引起的,并且通过dblink远端数据库执行时查询全变成的全表扫描,导致两个业务大表hash,业务高峰直接将数据库宕机,因此该hint添加或删除一定要看远端执行计划有无发生变化,否则后果不开设想(切记)。
㈣ 怎样保持Oracle数据库SQL性能的稳定性
有客户遇到SQL性能不稳定 突然变差导致系统性能出现严重问题的情况 对于大型的系统来说 SQL性能不稳定 有时突然变差 这是常常遇到的问题 这也是一些DBA的挑战
对于使用Oracle数据库的应用系统 有时会出现运行得好好的SQL 性能突然变差 特别是对于OLTP类型系统执行频繁的核心SQL 如果出现性能问题 通常会影响整个数据库的性能 进而影响整个系统的正常运行 对于个别的SQL 比如较少使用的查询报表之类的SQL 如果出现问题 通常只影响少部分功能模块 而不会影响整个系统
那么应该怎么样保持SQL性能的稳定性?
SQL的性能变差 通常是在SQL语句重新进行了解析 解析时使用了错误的执行计划出现的 下列情况是SQL会重新解析的原因
SQL语句没有使用绑定变量 这样SQL每次执行都要解析
SQL长时间没有执行 被刷出SHARED POOL 再次执行时需要重新解析
在SQL引用的对象(表 视图等)上执行了DDL操作 甚至是结构发生了变化 比如建了一个索引
对SQL引用的对象进行了权限更改森拿
重新分析(收集统计信息)了SQL引用的表和索引 或者表和索引统计信息被删除
修改了与性能相关的部分参数
刷新了共享池
当然重启数据库也会使所有SQL全部重新解析
SQL重新解析后 跟以前相比 性能突然变差 通常是下列原因
表和索引的优化统计信息被删除 或者重新收集后统计信息不准确 重新收集统计信息通常是由于收集策略(方法)不正确引起 比如对分区表使用 *** yze命令而不是用dbms_stats包 收集统计信息时采样比例过小等等 Oracle优化器严重依赖于统计信息 如果统计信息有问题 则很容易导致SQL不能使用正确的执行计划
SQL绑定变量窥蚂祥探(bind peeking) 同时绑定变量对应的列上有直方图 或者绑定变量的值变化范围过大 分区数据分布极不均匀
) 绑定变量的列上有闷春搏直方图
假如表orders存储所有的订单 state列有 种不同的值 表示未处理 表示处理成功完成 表示处理失败 State列上有一个索引 表中绝大部分数据的state列为 和 占少数 有下面的SQL
select * from orders where state=:b
这里:b 是变量 在大多数情况下这个值为 则应该使用索引 但是如果SQL被重新解析 而第一次执行时应用传给变量b 值为 则不会使用索引 采用全表扫描的方式来访问表 对于绑定变量的SQL 只在第一次执行时才会进行绑定变量窥探 并以此确定执行计划 该SQL后续执行时全部按这个执行计划 这样在后续执行时 b 变量传入的值为 的时候 仍然是第一次执行时产生的执行计划 即使用的是全表扫描 这样会导致性能很差
) 绑定变量的值变化范围过大
同样假如orders表有一列created_date表示一笔订单的下单时间 orders表里面存储了最近 年的数据 有如下的SQL
Select * from orders where created_date >=:b ;
假如大多数情况下 应用传入的b 变量值为最近几天内的日期值 那么SQL使用的是created_date列上的索引 而如果b 变量值为 个月之前的一个值 那么就会使用全表扫描 与上面描述的直方图引起的问题一样 如果SQL第 次执行时传入的变量值引起的是全表扫描 那么将该SQL后续执行时都使用了全表扫描 从而影响了性能
) 分区数据量不均匀
对于范围和列表分区 可能存在各个分区之间数据量极不均匀的情况下 比如分区表orders按地区area进行了分区 P 分区只有几千行 而P 分区有 万行数据 同时假如有一列proct_id 其上有一个本地分区索引 有如下的SQL
select * from orders where area=:b and proct_id =:b
这条SQL由于有area条件 因此会使用分区排除 如果第 次执行时应用传给b 变量的值正好落在P 分区上 很可能导致SQL采用全表扫描访问 如前面所描述的 导致SQL后续执行时全部使用了全表扫描
其他原因 比如表做了类似于MOVE操作之后 索引不可用 对索引进行了更改 当然这种情况是属于维护不当引起的问题 不在本文讨论的范围
综上所述 SQL语句性能突然变差 主要是因为绑定变量和统计信息的原因 注意这里只讨论了突然变差的情况 而对于由于数据量和业务量的增加性能逐步变差的情况不讨论
为保持SQL性能或者说是执行计划的稳定性 需要从以下几个方面着手
规划好优化统计信息的收集策略 对于Oracle g来说 默认的策略能够满足大部分需求 但是默认的收集策略会过多地收集列上的直方图 由于绑定变量与直方图固有的矛盾 为保持性能稳定 对使用绑定变量的列 不收集列上的直方图 对的确需要收集直方图的列 在SQL中该列上的条件就不要用绑定变量 统计信息收集策略 可以考虑对大部分表 使用系统默认的收集策略 而对于有问题的 可以用DBMS_STATS LOCK_STATS锁定表的统计信息 避免系统自动收集该表的统计信息 然后编写脚本来定制地收集表的统计信息 脚本中类似如下
exec dbms_stats unlock_table_stats…
exec dbms_stats gather_table_stats…
exec dbms_stats lock_table_stats…
修改SQL语句 使用HINT 使SQL语句按HINT指定的执行计划进行执行 这需要修改应用 同时需要逐条SQL语句进行 加上测试和发布 时间较长 成本较高 风险也较大
修改隐含参数 _optim_peek_user_binds 为FALSE 修改这个参数可能会引起性能问题(这里讨论的是稳定性问题)
使用OUTLINE 对于曾经出现过执行计划突然变差的SQL语句 可以使用OUTLINE来加固其执行计划 在 g中DBMS_OUTLN CREATE_OUTLINE可以根据已有的执行正常的SQL游标来创建OUTLINE 如果事先对所有频繁执行的核心SQL使用OUTLINE加固执行计划 将最大可能地避免SQL语句性能突然变差
注 DBMS_OUTLN可以通过$ORACLE_HOME/rdbms/admin/dbmsol sql脚本来安装
使用SQL Profile SQL Profile是Oracle g之后的新功能 此处不再介绍 请参考相应的文档
除此之外 可以调整一些参数避免潜在的问题 比如将 _btree_bitmap_plans 参数设置为FALSE(这个参数请参考互联网上的文章或Oracle文档)
lishixin/Article/program/Oracle/201311/18054