常用的SQL优化技巧
Posted Jane Chiu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了常用的SQL优化技巧相关的知识,希望对你有一定的参考价值。
从使用索引来考虑SQL语句
-
避免索引列上的函数,如SUBSTR/UPPER/NVL/TO_CHAR/TO_DATE/TRUNC
-
避免索引列上的计算公式:如果索引列上使用了计算公式,则索引不能使用,可以通过更改计算公式来避免
不使用索引:Select e.Ename From Emp e Where e.Sal * 1.1 > 900
使用索引:Select e.Ename From Emp e Where e.Sal > 900 / 1.1
低效: Select … FROM DEPARTMENT Where DEPT_CODE IS NOT NULL;
高效: Select … FROM DEPARTMENT Where DEPT_CODE >=0; -
避免使用not in,使用not exists代替
Select e.Ename From Emp e Where e.Deptno Not In (Select d.Deptno From Dept d)
Select e.Ename From Emp e Where e.Deptno Not Exists (Select ‘x’ From Dept d Where d.Deptno = e.Deptno) -
LIKE的使用: LIKE用于模糊检索,LIKE检索的样式有三种:前匹配(XX%)、中间匹配(X%X)、后匹配(%XX),对于前匹配可以使用索引,而使用中间匹配和后匹配,都不能使用索引。因此除非必要,否则应尽量避免使用中间匹配和后匹配
-
复合索引的使用:要使用复合索引,where语句中必须包括复合索引中的所有列或前几个列。如果复合索引的第一个列不在where语句中则不应该使用该复合索引
从减少系统负荷来考虑SQL语句
-
使用表别名:通过对表附加别名,SQL编译时可以明确列的来源表,从而使得SQL的编译时间缩短
-
ROWNUM的使用:ROWNUM可以限制检索数据的数量,如果为了判断对象是否存在,使用ROWNUM=1是非常有效的
-
UNION和UNION ALL:如果确定联合中不会出现重复数据的话,必须设定UNION ALL来取消自动分类以提高检索速度
-
替代DISTINCT:尽量少使用DISTINCT,使用DISTINCT将引起内部排序处理,如果可以的话,尽量使用EXISTS、NOT EXISTS或子查询来避免
Select Distinct d.Deptno, d.Dname From Dept d, Emp e Where d.Deptno = e.DeptnoSelect d.Deptno, d.Dname From Dept d Where Exists (Select ‘x’ From Emp e Where d.Deptno = e.Deptno) -
避免视图滥用:如果查询只检索基表的几个字段,应避免直接使用视图,造成不必要的数据块检索
-
编写可再利用性的SQL语句:需要动态组合条件时,应避免直接将变量值组合到条件中去,而应该使用变量绑定,从而提高SQL语句的再利用性
Select子句中避免使用*
当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用 * 是一个方便的方法.不幸的是,这是一个非常低效的方法. 实际上,ORACLE在解析的过程中, 会将 * 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间.
使用decode函数来减少处理时间
使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表.
例如:
select count() from pts_work_centers t where t.organization_id = 85
and t.work_center_name like ‘%氧化%’;
select count() from pts_work_centers t where t.organization_id = 86
and t.work_center_name like ‘%氧化%’;
用decode可以写成:
select count(decode(t.organization_id,85,‘X’)),
count(decode(t.organization_id,86,‘X’))
from pts_work_centers t
where t.work_center_name like ‘%氧化%’;
用Where子句替换HAVING子句
避免使用HAVING子句, HAVING 只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作. 如果能通过WHERE子句限制记录的数目,那就能减少这方面的开销.
低效:
select t.organization_id,count(*)
from pts_work_centers t
group by t.organization_id
having t.organization_id not in(85,86);
高效:
select t.organization_id,count(*)
from pts_work_centers t
where t.organization_id not in(85,86)
group by t.organization_id
HAVING 中的条件一般用于对一些集合函数的比较,如COUNT() 等等. 除此而外,一般的条件应该写在WHERE子句中
需要当心的Where子句:
某些Select 语句中的Where子句不使用索引. 这里有一些例子.
在下面的例子里
- ‘!=’ 将不使用索引. 记住, 索引只能告诉你什么存在于表中, 而不能告诉你什么不存在于表中.
- ‘||'是字符连接函数. 就象其他函数那样, 停用了索引.
- ‘+'是数学函数. 就象其他数学函数那样, 停用了索引.
- 相同的索引列不能互相比较,这将会启用全表扫描.
利用空值不会出现在索引的原则来提高SQL性能
假如某个字段,对于大多数记录而言是一个固定值,只有少数记录是另外其他值,而我们的程序中通常要查询这些少数据记录。
例如,库存事务表的‘成本核算’字段,大多数记录肯定是已核算成本,只有少部分记录是未核算成本,而成本管理器就仅仅想查询这些未核算成本的记录,如果我们设计‘已核算’状态的值为‘Y’,‘未核算’状态为‘N’,那这个查询会消耗巨大。如果我们设计‘已核算’状态的值为‘’,‘未核算’状态为‘N’,那么查询速度会非常快: select transaction_id from mmt where cost_flag = ‘N’
避免改变索引列的类型
避免ORACLE对你的SQL进行隐式的类型转换, 最好把类型转换用显式表现出来. 注意当字符和数值比较时, ORACLE会优先转换数值类型到字符类型.
假设 EMPNO是一个数值类型的索引列.
SELECT …
FROM EMP
WHERE EMPNO = ‘123’
实际上,经过ORACLE类型转换, 语句转化为:
SELECT …
FROM EMP
WHERE EMPNO = TO_NUMBER(‘123’)
幸运的是,类型转换没有发生在索引列上,索引的用途没有被改变.
现在,假设EMP_TYPE是一个字符类型的索引列.
SELECT …
FROM EMP
WHERE EMP_TYPE = 123
这个语句被ORACLE转换为:
SELECT …
FROM EMP
WHERE TO_NUMBER(EMP_TYPE)=123
因为内部发生的类型转换, 这个索引将不会被用到!
识别’低效执行’的SQL语句
用下列SQL找出低效SQL:
SELECT EXECUTIONS , DISK_READS, BUFFER_GETS,
ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2) Hit_radio,
ROUND(DISK_READS/EXECUTIONS,2) Reads_per_run,
SQL_TEXT
FROM V$SQLAREA
WHERE EXECUTIONS>0
AND BUFFER_GETS > 0
AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8
ORDER BY 4 DESC;
select * from (
select * from V$SQLSTATS
-- 最耗时的 SQL
-- ELAPSED_TIME 指的是总耗时(毫秒),平均耗时 = ELAPSED_TIME/EXECUTIONS
-- order by ELAPSED_TIME DESC
-- 查询执行次数最多的 SQL
-- order by EXECUTIONS DESC
-- 读硬盘最多的 SQL
-- order by DISK_READS DESC
-- 最费 CPU 的 SQL
-- order by BUFFER_GETS DESC
) where rownum <=50;
查找前十条性能差的sql
SELECT * FROM
(
SELECT PARSING_USER_ID
EXECUTIONS,
SORTS,
COMMAND_TYPE,
DISK_READS,
sql_text
FROM v$sqlarea
ORDER BY disk_reads DESC
) WHERE ROWNUM<10 ;
以上是关于常用的SQL优化技巧的主要内容,如果未能解决你的问题,请参考以下文章
《深入浅出Mysql》——第三篇 优化篇 第十七章 常用SQL技巧和常见问题 + 第十八章 SQL优化 + 第十九章 优化数据库对象