引言
对于下面的Oracle分页如何优化该段语句:
SELECT *
FROM (SELECT A.*, ROWNUM RN
FROM (SELECT * FROM task_log order by taskid desc) A
WHERE ROWNUM <= 40)
WHERE RN >= 21;
第一部分:
判断并获取问题SQL?
问题sql主要有以下两个表象
系统级别表象:
- CPU消耗严重
- IO等待严重
- 页面相应时间过长
SQL语句表象:
- 冗长
- 执行时间过长
- 从全表扫描获取数据
- PLAN的cost很大
第二部分:
SQL优化-基础篇
数据库设计的技巧:
- 主键设计
所有的表都应该有主键
主键尽量为单例
主键尽量采用INT类型
尽量避免使用字符、UUID作为主键
- 数据类型设计
尽量使用数字类型而非字符类型
尽量使用日期类型而非字符类型
定长字符可以考虑使用char类型
尽量选择最小的空间来存储数据
- 数据分割设计
采用垂直分割将热数据和冷数据拆分
采用水平分割或者分区实现减少表大小
- 减少递归查询的设计
避免connect by语法以join替代
采用存储过程实现connect by特性
- 范式化设计和反范式化设计
范式化设计优点:数据精简、DML效率高
范式化设计缺点:join时查询效率稍差
范式化设计适用环境:在线交易系统、需要严格事务支持的环境
反范式化设计优点:查询效率高,避免join
反范式化设计缺点:数据冗余、DML代价大
反范式化设计适用环境:数据仓库环境、无需事务支持的环境
- 对象放置设计
适合大型数据库设计
热数据冷数据分开存放
不同业务需求数据分开存放-成本考虑
在线交易及仓库数据分开存放
- 列位置设计
常用的列放在前面
列数量要尽可能少
SQL编写的技巧
- 合理使用索引
概念学习:
选择率的概念:重复值少的称之为选择率高;重复值多的称之为选择率低
索引层级的概念:索引越大,可能层级越多;索引层级越大,效率越低
Oracle索引扫描的类型:
-index unique scan
-index range scan
-index skip scan
-index fast full scan
-index full scan
使用建议:
选择率高且被where频繁引用需要建立B树索引
大表的join列需要建立索引
复杂文档类型查询采用全文索引效率更好
索引的建立要在查询和DML性能之间取得平衡
复合索引用法就是上一条的具体思考
第一步优化:
对于前面的那个优化的例子,在未建立索引之前,执行计划如下所示(主要关注红色箭头的位置)
尝试在排序字段建立索引:
drop index idx1;
create index idx1 on task_log(taskid desc);
exec dbms_stats.gather_schema_stats(ownname =>'SCOTT',options => 'GATHER',estimate_percent => null,method_opt=>'for all indexed columns',cascade=>true,degree=> 4 );
执行效果如下:
- 使用UNION ALL替代UNION
- 避免select *写法
- JOIN字段建议建立索引
- 避免复杂SQL语句
- 避免where 1=1写法
- 避免order by rand()类似写法
初步了解执行计划
Cost的概念:
成本表示优化器对执行语句所用时间的最优估计;
优化器主要分2种,CBO和RBO,对于新版本数据库,RBO已经基本淘汰。
CBO(基于代价的优化器)是RBO(基于规则的优化器)的替代品,从9i开始oracle就建议用户使用RBO来进行SQL的优化;
CBO大概的优化原理很简单,他通过对象上的统计信息来计算各个执行计划的代价,然后选择代价较小的执行计划来运行
对于CBO来说对象(比如表,索引)上的统计信息就显得十分的重要,不仅要有统计信息,还要保证统计信息是准确的,不准确的统计信息可能会带来灾难性的结果。
SQL优化-进阶篇
深入理解执行计划
了解执行计划的并行操作
了解执行计划的各种类型JOIN
了解执行计划的子查询相关
了解数据库参数对执行计划影响
10046事件跟踪
索引进阶使用技巧
位图索引
IOT
函数索引
聚簇因子
固化数据的技巧
物化视图和查询重写
全局临时表
with语句固化数据
使用分区修剪来优化查询
查询指定分区
查询不指定分区
固定执行计划
profile
outline
baseline
优化join方式
HASH JOIN
NEST LOOP JOIN
Sort merge join
STAR JOIN
使用HINT优化
first rows对分页SQL进行优化
index HINT强制使用INDEX
use_hash、use_nj改变join方法
并行hint/+*parallel(t 4)*/
第二步优化:尝试使用HINT
SELECT /*+ first_rows(20)*/*
FROM (SELECT A.*, ROWNUM RN
FROM (SELECT * FROM task_log order by taskid desc) A
WHERE ROWNUM <= 40)
WHERE RN >= 21;
SQL优化技能培养
个人:深入学习特定RDBMS
个人:熟能生巧
制度:重视数据库设计,从源头避免很多问题
制度:完善并遵循SQL编写规范