SQL优化速成

来源:互联网 发布:经纬切割机软件下载 编辑:程序博客网 时间:2024/05/29 09:22

1.索引

实际上,您可以把索引理解为一种特殊的目录。微软的SQLSERVER提供了两种索引:聚集索引(clustered index,也称聚类索引、簇集索引)和非聚集索引(nonclusteredindex,也称非聚类索引、非簇集索引)。

其实,我们的汉语字典的正文本身就是一个聚集索引。比如,我们要查“安”字,就会很自然地翻开字典的前几页,因为“安”的拼音是“an”,而按照拼音排序汉字的字典是以英文字母“a”开头并以“z”结尾的,那么“安”字就自然地排在字典的前部。如果您翻完了所有以“a”开头的部分仍然找不到这个字,那么就说明您的字典中没有这个字;同样的,如果查“张”字,那您也会将您的字典翻到最后部分,因为“张”的拼音是“zhang”。也就是说,字典的正文部分本身就是一个目录,您不需要再去查其他目录来找到您需要找的内容。我们把这种正文内容本身就是一种按照一定规则排列的目录称为“聚集索引”。

如果您认识某个字,您可以快速地从自动中查到这个字。但您也可能会遇到您不认识的字,不知道它的发音,这时候,您就不能按照刚才的方法找到您要查的字,而需要去根据“偏旁部首”查到您要找的字,然后根据这个字后的页码直接翻到某页来找到您要找的字。但您结合“部首目录”和“检字表”而查到的字的排序并不是真正的正文的排序方法,比如您查“张”字,我们可以看到在查部首之后的检字表中“张”的页码是672页,检字表中“张”的上面是“驰”字,但页码却是63页,“张”的下面是“弩”字,页面是390页。很显然,这些字并不是真正的分别位于“张”字的上下方,现在您看到的连续的“驰、张、弩”三字实际上就是他们在非聚集索引中的排序,是字典正文中的字在非聚集索引中的映射。我们可以通过这种方式来找到您所需要的字,但它需要两个过程,先找到目录中的结果,然后再翻到您所需要的页码。我们把这种目录纯粹是目录,正文纯粹是正文的排序方式称为“非聚集索引”。

通过以上例子,我们可以理解到什么是“聚集索引”和“非聚集索引”。进一步引申一下,我们可以很容易的理解:每个表只能有一个聚集索引,因为目录只能按照一种方法进行排序。

对查询进行优化,要尽量避免全表扫描,首先应考虑在where 及 order by 涉及的列上建立索引。

 如果检索数据量超过30%的表中记录数.使用索引将没有显著的效率提高.  在特定情况下, 使用索引也许会比全表扫描慢, 但这是同一个数量级上的区别.而通常情况下,使用索引比全表扫描要块几倍乃至几千倍!

创建聚集索引(SQLSERVER

CREATE CLUSTEREDINDEX INDEX_NAME ON TABLENAME(COLUMN1)

创建非聚集索引(SQLSERVER

CREATE NONCLUSTEREDINDEX INDEX_NAME on TABLENAME(COLUMN1,COLUMN2...)

 

2.避免使用模糊匹配

尽量避免在一个复杂查询里面使用 LIKE'%parm1%'—— 红色标识位置的百分号会导致相关列的索引无法使用,最好不要用.

 

3.复杂操作

部分UPDATE、SELECT 语句写得很复杂(经常嵌套多级子查询)——可以考虑适当拆成几步,先生成一些临时数据表,再进行关联操作,慎重使用临时表可以极大的提高系统性能

临时表创建方法

SELECT *INTO #TEMPTABLE FROM TABLENAME

 

4.在可以使用UNIONALL的语句里,使用了UNION

UNION因为会将各查询子集的记录做比较,故比起UNION ALL ,通常速度都会慢上许多。一般来说,如果使用UNION ALL能满足要求的话,务必使用UNIONALL。还有一种情况大家可能会忽略掉,就是虽然要求几个子集的并集需要过滤掉重复记录,但由于脚本的特殊性,不可能存在重复记录,这时便应该使用UNIONALL,如xx模块的某个查询程序就曾经存在这种情况,见,由于语句的特殊性,在这个脚本中几个子集的记录绝对不可能重复,故可以改用UNION ALL)

 

 

5.在WHERE语句中,尽量避免对索引字段进行计算操作

 

对索引字段进行才做,会使索引无法用上

where trunc(create_date)=trunc(:date1)

应该写成where create_date betweentrunc(:date1) and trunc(:date1)+1-1/(24*60*60)

 

 

6.对Where 语句的法则

 

避免在WHERE子句中使用INNOT INOR或者HAVING。用EXISTS替代IN、用NOT EXISTS替代NOT IN

不要以字符格式声明数字,要以数字格式声明字符值。(日期同样)否则会使索引无效,产生全表扫描。

应尽量避免在 where 子句中对字段进行null 值判断,否则将导致引擎放弃使用索引而进行全表扫描

SELECT emp.ename, emp.job FROM emp WHERE emp.empno = 7369;

不要使用:SELECT emp.ename, emp.job FROM emp WHERE emp.empno ='7369'

 

7.对Select语句的法则

在应用程序、包和过程中限制使用select * from table这种方式。看下面例子

使用SELECT empno,ename,category FROM emp WHERE empno = 7369

而不要使用SELECT * FROM emp WHERE empno = 7369

 

8. 排序

避免使用耗费资源的操作,带有DISTINCT,UNION,MINUS,INTERSECT,ORDERBY的SQL语句会启动SQL引擎 执行,耗费资源的排序(SORT)功能. DISTINCT需要一次排序操作, 而其他的至少需要执行两次排序

 

19.WHERE子句中的连接顺序

Oracle采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前,那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾。

 

10.使用表的别名(Alias) 

当在SQL语句中连接多个表时,请使用表的别名并把别名前缀于每个Column上。这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误。