首页 > 代码库 > 长沙做网站公司解密如何编写高效率的SQL语句

长沙做网站公司解密如何编写高效率的SQL语句

如何书写高效的SQL语句 长沙做网站公司在应用开发中,书写SQL语句是最基本的工作,但我们往往在这方面侧重的是功能的实现,很容易把效率问题给忽略了,在随着系统数据的不断增加,可能有些低效的SQL语句会让客户感觉系统反映缓慢,甚至还有可能会因长时间执行不出结果而报超时或其它系统错误,所以我们要养成一个良好的编码习惯,不仅要实现其功能,而且要尽可能的提高效率。 下面内容是在网络上收集的一些比较典型实用的优化点,以及在工作中用到的典型样例,供大家参考学习。1、注意UNion和UNion all 的区别。   它们两都可以把相同结果集并在一起,但UNION all的效率稍好一些,在就是如果A并上B有重复记录,union all可以把重复数据distict掉2、注意使用DISTINCT,在没有必要时不要用,它同UNION一样会使查询变慢。重复的记录在查询里是没有问题的 3、查询时不要返回不需要的行、列 ,即最好不要用select * from tablename,这样会把所有的字段都解析出来.4、如果使用了IN或者OR等时发现查询没有走索引,使用显示申明指定索引:      SELECT   *   FROM   PersonMember   (INDEX   =   IX_Title)   WHERE   processid   IN   (‘男’,‘女’) 5、在SQL2000以前,一般不要用如下的字句:   "IS   NULL",   " <> ",   "!=",   "!> ",   "! <",   "NOT",   "NOT   EXISTS",   "NOT   IN",   "NOT   LIKE",   and   "LIKE%500’",因为他们不走索引全是表扫描。也不要在WHere字句中的列名加函数,如Convert,substring等,如果必须用函数的时候,创建计算列再创建索引来替代.还可以变通写法:WHERE   SUBSTRING(firstname,1,1)   =   ’m’改为WHERE   firstname   like  ’m%’(索引扫描),一定要将函数和列名分开。并且索引不能建得太多和太大。NOT   IN会多次扫描表,使用EXISTS、NOT   EXISTSIN   ,   LEFT   OUTER   JOIN   来替代,特别是左连接,而Exists比IN更快,最慢的是NOT操作.如果列的值含有空,以前它的索引不起作用,现在2000的优化器能够处理了。相同的是IS   NULL,“NOT",   "NOT   EXISTS",   "NOT   IN"能优化她,而” <> ”等还是不能优化,用不到索引。 对于like的高效使用方法 本站有详细的讲解。6、将需要查询的结果预先计算好放在表中,查询的时候再SELECT。这在SQL7.0以前是最重要的手段。例如医院的住院费计算。 7MIN() 和 MAX()能使用到合适的索引 8、数据库有一个原则是代码离数据越近越好,所以优先选择Default,依次为Rules,Triggers,   Constraint(约束如外健主健CheckUNIQUE……,数据类型的最大长度等等都是约束),Procedure.这样不仅维护工作小,编写程序质量高,并且执行的速度快。  9、如果要插入大的二进制值到Image列,使用存储过程,千万不要用内嵌INsert来插入(不知JAVA是否)。因为这样应用程序首先将二进制值转换成字符串(尺寸是它的两倍),服务器受到字符后又将他转换成二进制值.存储过程就没有这些动作:   方法:Create   procedure   p_insert   as   insert   into   table(Fimage)   values   (@image),   在前台调用这个存储过程传入二进制参数,这样处理速度明显改善。 10、Between在某些时候比IN速度更快,Between能够更快地根据索引找到范围。用查询优化器可见到差别。   select   *   from   chineseresume   where   title   in   (’男’,’女’)   Select   *   from  chineseresume   where   between   ’男’   and   ’女’   是一样的。由于in会在比较多次,所以有时会慢些。 11、在必要是对全局或者局部临时表创建索引,有时能够提高速度,但不是一定会这样,因为索引也耗费大量的资源。他的创建同是实际表一样。 12、不要建没有作用的事物例如产生报表时,浪费资源。只有在必要使用事物时使用它。         13、用OR的字句可以分解成多个查询,并且通过UNION   连接多个查询。他们的速度只同是否使用索引有关,如果查询需要用到联合索引,用UNION   all执行的效率更高.多个OR的字句没有用到索引,改写成UNION的形式再试图与索引匹配。一个关键的问题是否用到索引。 14、对于长沙网站建设开发的来说我们尽量少用视图,因为它的效率低。对视图操作比直接对表操作慢,可以用stored   procedure来代替她。特别的是不要用视图嵌套,嵌套视图增加了寻找原始资料的难度。我们看视图的本质:它是存放在服务器上的被优化好了的已经产生了查询规划的SQL。对单个表检索数据时,不要使用指向多个表的视图,直接从表检索或者仅仅包含这个表的视图上读,否则增加了不必要的开销,查询受到干扰.为了加快视图的查询,MsSQL增加了视图索引的功能。 15、没有必要时不要用DISTINCT和ORDER   BY,这些动作可以改在客户端执行。它们增加了额外的开销。这同UNION   和UNION   ALL一样的道理。 16、在IN后面值的列表中,将出现最频繁的值放在最前面,出现得最少的放在最后面,减少判断的次数 17、当用SELECT   INTO时,它会锁住系统表(sysobjects,sysindexes等等),阻塞其他的连接的存取。创建临时表时用显示申明语句,而不是 select   INTO.   drop   table   t_lxh   begin   tran   select   *  into   t_lxh   from   chineseresume   where   name   =   ’XYZ’   --commit   在另一个连接中SELECT   *   from   sysobjects可以看到   SELECT   INTO   会锁住系统表,Create   table   也会锁系统表(不管是临时表还是系统表)。所以千万不要在事物内使用它!!!这样的话如果是经常要用的临时表请使用实表,或者临时表变量。 18、一次更新多条记录比分多次更新每次一条快,就是说批处理好 19SELECT   COUNT(*)的效率教低,尽量变通他的写法,而EXISTS快.同时请注意区别:   select   count(Field   of   null)   from   Tableselect   count(Field   of   NOT   null)   from   Table   的返回值是不同的。 20、当服务器的内存够多时,配制线程数量   =   最大连接数+5,这样能发挥最大的效率;否则使用   配制线程数量 <最大连接数启用SQL   SERVER的线程池来解决,如果还是数量   =   最大连接数+5,严重的损害服务器的性能。 我觉得主要应该从5个方面进行调整: 1.去掉不必要的大型表的全表扫描 2.缓存小型表的全表扫描 3.检验优化索引的使用 4.检验优化的连接技术 5.尽可能减少执行计划的Cost现在简单的举几个例子Where子句中有“!=”将不使用索引 select account_name from test where amount != 0  (不使用) select account_name from test where amount > 0  (使用)Where条件中对字段增加处理函数将不使用该列的索引 select * from emp where to_char(hire_date,’yyyymmdd’)=20080411’ (不使用) select * from emp where hire_date = to_char(’20080411’,’yyyymmdd’) (使用)避免在索引列上使用IS NULL和 IS NOT NULL select * from emp where dept_code is not null  (不使用) select * from emp where dept_code > 0  (使用)通配符% 的使用 select * from emp where name like%A’  (不使用索引) select * from emp where name like ’A%’  (使用索引)最高效的删除重复记录方法 ( 因为使用了ROWID)例子: DELETE  FROM  EMP E  WHERE  E.ROWID > (SELECT MIN(X.ROWID) FROM  EMP X  WHERE  X.EMP_NO = E.EMP_NO);sql语句用大写的;因为oracle总是先解析sql语句,把小写的字母转换成大写的再执行在java代码中用到preparedStatement的時候尽量少用连接符“+”连接字符串!1. SELECT子句中避免使用 ‘*’    当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用 ‘*’ 是一个方便的方法.不幸的是,这是一个非常低效的方法. 实际上,ORACLE在解析的过程中, 会将’*’ 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间.2.选择最有效率的表名顺序(只在基于规则的优化器中有效)     ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表 driving table)将被最先处理. 在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表.当ORACLE处理多个表时, 会运用排序及合并的方式连接它们.首先,扫描第一个表(FROM子句中最后的那个表)并对记录进行派序,然后扫描第二个表(FROM子句中最后第二个表),最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并.例如: 表 TAB1 16,384 条记录      表 TAB2 1      条记录     选择TAB2作为基础表 (最好的方法)     select count(*) from tab1,tab2   执行时间0.96秒     选择TAB2作为基础表 (不佳的方法)     select count(*) from tab2,tab1   执行时间26.09秒如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表.例如:   EMP表描述了LOCATION表和CATEGORY表的交集.SELECT * FROM LOCATION L ,       CATEGORY C,      EMP E WHERE E.EMP_NO BETWEEN 1000 AND 2000AND E.CAT_NO = C.CAT_NOAND E.LOCN = L.LOCN将比下列SQL更有效率SELECT * FROM EMP E ,LOCATION L ,       CATEGORY CWHERE E.CAT_NO = C.CAT_NOAND E.LOCN = L.LOCNAND E.EMP_NO BETWEEN 1000 AND 20003. WHERE子句中的连接顺序.   ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾.例如:(低效,执行时间156.3秒)SELECTFROM EMP EWHERE SAL > 50000AND    JOB = ‘MANAGER’AND    25 < (SELECT COUNT(*) FROM EMP             WHERE MGR=E.EMPNO);(高效,执行时间10.6秒)SELECTFROM EMP EWHERE 25 < (SELECT COUNT(*) FROM EMP             WHERE MGR=E.EMPNO)AND    SAL > 50000AND    JOB = ‘MANAGER’;4. 减少访问数据库的次数   当执行每条SQL语句时, ORACLE在内部执行了许多工作: 解析SQL语句, 估算索引的利用率, 绑定变量 , 读数据块等等. 由此可见, 减少访问数据库的次数 , 就能实际上减少ORACLE的工作量.例如,    以下有三种方法可以检索出雇员号等于0342或0291的职员.方法1 (最低效)    SELECT EMP_NAME , SALARY , GRADE    FROM EMP     WHERE EMP_NO = 342;     SELECT EMP_NAME , SALARY , GRADE    FROM EMP     WHERE EMP_NO = 291;方法2 (次低效)       DECLARE         CURSOR C1 (E_NO NUMBER) IS         SELECT EMP_NAME,SALARY,GRADE        FROM EMP         WHERE EMP_NO = E_NO;    BEGIN         OPEN C1(342);        FETCH C1 INTO …,..,.. ;                OPEN C1(291);       FETCH C1 INTO …,..,.. ;         CLOSE C1;      END;方法3 (高效)    SELECT A.EMP_NAME , A.SALARY , A.GRADE,            B.EMP_NAME , B.SALARY , B.GRADE    FROM EMP A,EMP B    WHERE A.EMP_NO = 342    AND   B.EMP_NO = 291;注意:在SQL*Plus , SQL*Forms和Pro*C中重新设置ARRAYSIZE参数, 可以增加每次数据库访问的检索数据量 ,建议值为200.5.使用DECODE函数来减少处理时间   使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表.例如:   SELECT COUNT(*),SUM(SAL)   FROM EMP   WHERE DEPT_NO = 0020   AND ENAME LIKE ‘SMITH%’;   SELECT COUNT(*),SUM(SAL)   FROM EMP   WHERE DEPT_NO = 0030   AND ENAME LIKE ‘SMITH%’;你可以用DECODE函数高效地得到相同结果SELECT COUNT(DECODE(DEPT_NO,0020,’X’,NULL)) D0020_COUNT,        COUNT(DECODE(DEPT_NO,0030,’X’,NULL)) D0030_COUNT,        SUM(DECODE(DEPT_NO,0020,SAL,NULL)) D0020_SAL,        SUM(DECODE(DEPT_NO,0030,SAL,NULL)) D0030_SALFROM EMP WHERE ENAME LIKE ‘SMITH%’;类似的,DECODE函数也可以运用于GROUP BY 和ORDER BY子句中.6 使用表的别名(Alias)   当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误.(译者注: Column歧义指的是由于SQL中不同的表具有相同的Column名,当SQL语句中出现这个Column时,SQL解析器无法判断这个Column的归属)7. 用EXISTS替代IN在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下, 使用EXISTS(或NOT EXISTS)通常将提高查询的效率.低效:SELECT * FROM EMP (基础表)WHERE EMPNO > 0AND DEPTNO IN (SELECT DEPTNO FROM DEPT WHERE LOC = ‘MELB’)    高效:SELECT * FROM EMP (基础表)WHERE EMPNO > 0AND EXISTS (SELECT ‘X’ FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNOAND LOC = ‘MELB’)(译者按: 相对来说,用NOT EXISTS替换NOT IN 将更显著地提高效率,下一节中将指出)8. 用NOT EXISTS替代NOT IN     在子查询中,NOT IN子句将执行一个内部的排序和合并. 无论在哪种情况下,NOT IN都是最低效的 (因为它对子查询中的表执行了一个全表遍历). 为了避免使用NOT IN ,我们可以把它改写成外连接(Outer Joins)或NOTEXISTS.例如:SELECTFROM EMPWHERE DEPT_NO NOT IN (SELECT DEPT_NO                          FROM DEPT                          WHERE DEPT_CAT=’A’);为了提高效率.改写为:(方法一: 高效)SELECT ….FROM EMP A,DEPT BWHERE A.DEPT_NO = B.DEPT(+)AND B.DEPT_NO IS NULLAND B.DEPT_CAT(+) = ‘A’(方法二: 最高效)SELECT ….FROM EMP EWHERE NOT EXISTS (SELECT ‘X’                     FROM DEPT D                    WHERE D.DEPT_NO = E.DEPT_NO                    AND DEPT_CAT = ‘A’);9. 用表连接替换EXISTS     通常来说 , 采用表连接的方式比EXISTS更有效率      SELECT ENAME      FROM EMP E      WHERE EXISTS (SELECT ‘X’                       FROM DEPT                      WHERE DEPT_NO = E.DEPT_NO                      AND DEPT_CAT = ‘A’);     (更高效)      SELECT ENAME      FROM DEPT D,EMP E      WHERE E.DEPT_NO = D.DEPT_NO      AND DEPT_CAT = ‘A’ ;   10.   用EXISTS替换DISTINCT当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT. 一般可以考虑用EXIST替换例如:低效:    SELECT DISTINCT DEPT_NO,DEPT_NAME    FROM DEPT D,EMP E    WHERE D.DEPT_NO = E.DEPT_NO高效:    SELECT DEPT_NO,DEPT_NAME    FROM DEPT D    WHERE EXISTS ( SELECT ‘X’                    FROM EMP E                    WHERE E.DEPT_NO = D.DEPT_NO);EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果.11. 用外连接代替NOT EXISTS低效写法:select count(t.fid)       from tableA t       where not exists       (select t1.fid                 from tableB t1                where t.fid = t1.fid)          and t.fdatastatus = ’unrelease’          and t.fdevicetypeid in              (select t2.fid from tableC t2 where t2.fcategory = ’保护’);高效写法:select count(t.fid)        from tableA t, tableB t1        where t.fid = t1.fid(+)        and t.fdatastatus = ’unrelease’        and t.fdevicetypeid in             (select t2.fid from tableC t2 where t2.fcategory = ’保护’)        and t1.fid is null;条件1:tableA表中有181901 ,tableB表中有195条数据;查出满足条件的数据4798   低效写法用时:2.2874秒   高效写法用时:0.8814秒条件2:tableA表中有298870 ,tableB表中有89338条数据;查出满足条件的数据30909   低效写法用时:半小时执行不出结果(直接费了)   高效写法用时:6.2964秒注:通过上面两条SQL语句分析,除法(不包含)用not exists的执行效率在数据量大的情况下也是很低的,我们可以通过左右链接的方法同样能满足这样的需求,且效率上有惊人的变化。转载请注明www.sendawangluo.com

 

长沙做网站公司解密如何编写高效率的SQL语句