zoukankan      html  css  js  c++  java
  • SQL优化总结

    http://www.cnblogs.com/baiyu/archive/2011/09/21/2183809.html

    http://www.cnblogs.com/zengxiangzhan/archive/2009/12/04/1617186.html

    /*常见优化建议*/

    1、UNION会对结果进行排序,尽量用UNION ALL 替换(比如在不可能有重复记录时)


    2、用>=代替>,高效: WHERE DEPTNO >=4,低效: WHERE DEPTNO >3,=号可以直接定位


    3、用WHERE子句替换HAVING子句,将不需要的记录在GROUP BY之前过滤掉


    4、复杂的SQL往往牺牲了执行效率,尽量通过内部函数提高SQL效率


    5、连接多个表时, 使用表的别名并把别名前缀于每个列上,可以减少解析时间和理解歧义


    6、视情况,可用EXISTS替代IN、用NOT EXISTS替代NOT IN
      低效:SELECT * FROM EMP WHERE DEPTNO IN(SELECT DEPTNO FROM DEPT WHERE LOC = 'MELB')
      高效:SELECT * FROM EMP WHERE EXISTS (SELECT 'X' FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = 'MELB')

    7、视情况,NOT IN 可以用 LEFT JOIN ... WHERE ... IS NULL 代替

    8、考虑使用临时表或表变量存放中间结果,把连接拆成较小的几个部分逐个顺序执行,优先执行那些能够大量减少结果的连接。好处不仅仅是减少SQL SERVER优化的时间,更使得SQL语句能够以你可以预测的方式和顺序执行。比如连接的where条件都是针对TableA的,可以这样拆分:
    select * into #tmp from TableA where...
    select * from #tmp left join TableB on #tmp.BID = TableB.BID

     a、局部临时表(#tmp)只对当前连接有效,当前连接断开时自动删除。
     b、全局临时表(##tmp)对其它连接也有效,在当前连接和其他访问过它的连接都断开时自动删除。 
     c、不管局部临时表还是全局临时表,只要连接有访问权限,都可以用drop table #tmp(或者drop table ##tmp)来显式删除

     d、如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table,然后 drop table,这样可以避免系统表的较长时间锁定。

     

    9、若只含数值信息的字段尽量使用数字型字段,不要设计为字符型


    /*对于索引*/


    1、!=将不使用索引, 索引只能告诉你什么存在于表中, 而不能告诉你什么不存在于表中


    2、避免对索引计算
    ,低效: WHERE SAL * 12 > 25000,高效: WHERE SAL > 25000/12


    3、索引列间的OR会造成全表扫描,用UNION代替OR如 SELECT ID FROM T WHERE NUM=10 OR NUM=20 可以这样查询:
         SELECT ID FROM T WHERE NUM=10 UNION ALL SELECT ID FROM T WHERE NUM=20


    4、避免在索引列上使用IS NULL和IS NOT NULL,低效: WHERE CODE IS NOT NULL,高效: WHERE CODE >=0;


    5、总是使用联合索引的第一个列, 只有在联合索引的第一个列被WHERE子句引用时,索引才生效

    6、用<和>代替<>,<和>允许使用索引,而<>不可以

      低效:SELECT * FROM EMP WHERE SALARY<>3000

      高效:SELECT * FROM EMP WHERE SALARY<3000 OR SALARY>3000

    7、尽量避免把通配符%放到词首,使用WHERE NAME LIKE 'JACK%',这样可以使用索引

    8、对于连续的数值,能用 between 就不要用 in:select id from t where num between 1 and 3

    9、一定要将函数和列名分开,如变通写法:SUBSTRING(name,1,1)='m' 改为 name like 'm%'(索引扫描)

    /*关于视图*/

    无法在视图 'view_xxxx' 上创建索引,因为该视图未绑定到架构
    解决办法:重新设计视图,在视图设计语句之前加上:ALTER VIEW View_LotteryIssue WITH SCHEMABINDING as 原视图设计语句
    无法在视图 'view_xxxx' 上创建索引,因为其中包含表提示
    解决办法:去掉表提示,如wiht nolock

    一般视图(没有索引): 聚焦特定的数据,防止敏感的列被选中;简化频繁书写操作,一些复杂的逻辑操作放在视图中完成,简化了外部查询语句;
    索引视图:提高查询的效率

    视图中不要使用ORDER BY,在查询视图时再ORDER BY。
    视图性能较低,可以用存储过程代替。
    不要用视图嵌套,嵌套视图增加了寻找原始资料的难度。

    /*临时表#/##与表变量@/@@*/

     

    http://www.cnblogs.com/vs2020/archive/2012/02/06/2339532.html
    临时表存放在磁盘;用于较大的数据集;需要日志,可以创建索引,可以使用统计数据,可以在多会话中访问,需要锁机制。
    表变量存放在内存;用于较小的数据集;不需要日志,不可以创建索引,不可以使用统计数据,不可以在多会话中访问,不需要锁机制。

    创建临时表时用显示申明语句,而不是SELECT INTO。
    当用SELECT INTO或CREATE TABLE时,它会锁住系统表(sysobjects,sysindexes等等),阻塞其他的连接的存取,所以千万不要在事务内使用!


    如果是经常要用的临时表请使用实表,或者临时表变量。

    /*对于ORACLE*/


    1、ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(即基础表)将被最先处理


    2、在FROM子句中包含多个表的情况下,选择记录条数最少的表作为基础表


     3、如果有3个以上的表连接查询,那就需要选择交叉表(被其他表所引用的表)作为基础表


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


    5、明确列名,避免使用SELECT *,ORACLE在解析的过程中, 会将*依次转换成所有的列名, 这个工作是通过查询数据字典完成的

    /*查询慢的原因*/

     

    1、没有索引或者没有用到索引或没有用到预想中的索引:可以指定索引 (index =索引名)

    2、查询出的数据量过大:使用纵/横向分割表、多次查询、需求分解,降低数据量 

    3、锁或者死锁:nolock、增加冗余列减少计算
     
    4、返回了不必要的行或列:补充条件,指定返回列名

    5、查询字段值很长:不用like,而是建全文索引

    6、插入大的二进制值到Image列,使用存储过程(或带参的SQL),不要用内嵌Insert来插入(需要二进制转字符串再转二进制)。
    CREATE PROCEDURE p_insert AS INSERT INTO TABLE(t) VALUES (@image)

    7、在IN后面值的列表中,将出现最多的放前面,出现最少的放后面(in多少) 

    8、如果GROUP BY的目的不包括计算,只是分组,那么用DISTINCT更快 

    9、批处理。一次更新多条记录比分多次更新每次一条快 

    10、存储过程。尽量将数据的处理工作放在服务器上,减少网络的开销,如使用存储过程。反复执行的动态SQL,可以使用临时存储过程(CREATE PROCEDURE #p_tmp)。 

    11、锁表顺序。按照一定的次序来访问你的表。如果你先锁住表A,再锁住表B,那么在所有的存储过程中都要按照这个顺序来锁定它们。
    如果你(不经意的)某个存储过程中先锁定表B,再锁定表A,这可能就会导致一个死锁,死锁很难被发现。

    12、明确类型。分析WHERE SALARY > 3000,若SALARY是FLOAT类型的,则DBMS将对其进行优化为Convert(float,3000)。应在编程时直接使用3000.0。字符和整型的转换同理。

  • 相关阅读:
    31. Ubuntu15.04系统中如何启用、禁用客人会话
    dpkg安装deb缺少依赖包的解决方法
    C语言宏中"#"和"##"的用法
    编译android6.0错误recipe for target 'out/host/linux-x86/obj/lib/libart.so' failed
    Android api level对照表
    Android 如何判断CPU是32位还是64位
    vim map nmap(转)
    vim配置及插件安装管理(超级详细)
    Java多线程总结(二)锁、线程池
    Python快速教程目录(转)
  • 原文地址:https://www.cnblogs.com/vipcjob/p/2320292.html
Copyright © 2011-2022 走看看