• SQL优化让你的SQL运行得更快


    在使用SQL往往会陷入一个区,即太注于所得的果是否正确,而忽略了不同的实现方法之可能存在的性能差异,这种性能差异在大型的或是复杂的数据库环境中(如机事务处OLTP或决策支持系DSS)中表得尤
    笔者在工作践中发现,不良的SQL往往来自于不恰当的索引设计、不充份的接条件和不可化的where子句。
    们进行适当的化后,其运行速度有了明地提高!
    下面我将从三个方面分别进总结
    了更直问题,所有例中的SQL运行时间经过测试,不超1秒的均表示< 1秒)。----
    测试环主机:HP LH II---- 330MHZ---- 内存:128----
    操作系Operserver5.0.4----
    数据Sybase11.0.3
     
    一、不合理的索引设计----
    例:表record620000行,看在不同的索引下,下面几个 SQL的运行情况:
    ---- 1.date上建有一非个群集索引
    select count(*) from record where date >'19991201' and date < '19991214'and amount >2000 (25)
    select date ,sum(amount) from record group by date(55)
    select count(*) from record where date >'19990901' and place in ('BJ','SH') (27)
    ---- 分析:----
    date上有大量的重复值,在非群集索引下,数据在物理上随机存放在数据上,在范围查,必须执行一次表描才能找到一范内的全部行。
    ---- 2.date上的一个群集索引
    select count(*) from record where date >'19991201' and date < '19991214' and amount >2000 14秒)
    select date,sum(amount) from record group by date28秒)
    select count(*) from record where date >'19990901' and place in ('BJ','SH')14秒)
    ---- 分析:---- 在群集索引下,数据在物理上按序在数据上,重复值也排列在一起,因而在范围查,可以先找到个范的起末点,且只在个范描数据,避免了大范围扫描,提高了查询速度。
    ---- 3.placedateamount上的合索引
    select count(*) from record where date >'19991201' and date < '19991214' and amount >2000 26秒)
    select date,sum(amount) from record group by date27秒)
    select count(*) from record where date >'19990901' and place in ('BJ, 'SH')< 1秒)
    ---- 分析:---- 是一个不很合理的合索引,因它的前列是place,第一和第二条SQL没有引用place,因此也没有利用上索引;第三个SQL使用了place,且引用的所有列都包含在合索引中,形成了索引覆盖,所以它的速度是非常快的。
    ---- 4.dateplaceamount上的合索引
    select count(*) from record where date >'19991201' and date < '19991214' and amount >2000(< 1)
    select date,sum(amount) from record group by date11秒)
    select count(*) from record where date >'19990901' and place in ('BJ','SH')< 1秒)
    ---- 分析:---- 是一个合理的合索引。它将date列,使SQL都可以利用索引,并且在第一和第三个SQL中形成了索引覆盖,因而性能达到了最
    ---- 5.总结----
    缺省情况下建立的索引是非群集索引,但有它并不是最佳的;合理的索引设计要建立在种查询的分析和预测上。
    一般来
    .有大量重复值、且常有范围查询between, >,< >=,< =)和order bygroup by生的列,可考建立群集索引;
    .常同存取多列,且列都含有重复值可考建立合索引;
    .合索引要尽量使关键查询形成索引覆盖,其前列一定是使用最繁的列。
     
    二、不充份的接条件:
    例:表card7896行,在card_no上有一个非聚集索引,表account191122行,在account_no上有一个非聚集索引,看在不同的表接条件下,两个SQL行情况:
    select sum(a.amount) from account a,card b where a.card_no = b.card_no20秒)
    select sum(a.amount) from account a,card b where a.card_no = b.card_no and a.account_no=b.account_no< 1秒)
    ---- 分析:---- 在第一个接条件下,最佳查询方案是将account作外表,card作内表,利用card上的索引,其I/O次数可由以下公式估算
    account上的22541+(外account191122*card对应表第一行所要找的3=595907I/O
    在第二个接条件下,最佳查询方案是将card作外表,account作内表,利用account上的索引,其I/O次数可由以下公式估算:外card上的1944+(外card7896*account对应一行所要找的4= 33528I/O
    ,只有充份的接条件,真正的最佳方案才会被行。
    总结
    1.多表操作在被实际执行前,查询优化器会根据接条件,列出几可能的接方案并从中找出系统开销最小的最佳方案。接条件要充份考虑带有索引的表、行数多的表;内外表的选择可由公式:外表中的匹配行数*表中一次找的次数确定,乘最小最佳方案。
    2.行方案的方法-- set showplanon,打showplan选项,就可以看到序、使用何索引的信息;想看更详细的信息,需用sa角色dbcc(3604,310,302)
     
    三、不可化的where子句
    1.例:下列SQL条件句中的列都建有恰当的索引,但行速度却非常慢:
    select * from record wheresubstring(card_no,1,4)='5378'(13)
    select * from record whereamount/30< 100011秒)
    select * from record whereconvert(char(10),date,112)='19991201'10秒)
    分析:
    where子句中列的任何操作果都是在SQL运行逐列算得到的,因此它不得不行表搜索,而没有使用列上面的索引;
    如果果在查询编译时就能得到,那就可以被SQL化器化,使用索引,避免表搜索,因此将SQL重写成下面这样
    select * from record where card_no like'5378%'< 1秒)
    select * from record where amount< 1000*30< 1秒)
    select * from record where date= '1999/12/01'< 1秒)
    你会发现SQL快起来!
    2.例:表stuff200000行,id_no上有非群集索引,看下面SQL
    select count(*) from stuff where id_no in('0','1')23秒)
    分析:---- where条件中的'in'逻辑上相当于'or',所以法分析器会将in ('0','1')id_no ='0' or id_no='1'行。
    期望它会根据or子句分别查找,再将果相加,这样可以利用id_no上的索引;
    实际上(根据showplan,它却采用了"OR策略",即先取出or子句的行,存入临时数据的工作表中,再建立唯一索引以去掉重行,最后从临时表中果。因此,实际过程没有利用id_no上索引,并且完成时间还要受tempdb数据性能的影响。
    明,表的行数越多,工作表的性能就越差,当stuff620000时间竟达到220秒!不如将or子句分
    select count(*) from stuff where id_no='0'select count(*) from stuff where id_no='1'
    得到两个果,再作一次加法合算。因为每句都使用了索引,时间只有3秒,在620000行下,时间也只有4秒。
    或者,用更好的方法,写一个简单的存储过程:
    create proc count_stuff asdeclare @a intdeclare @b intdeclare @c intdeclare @d char(10)beginselect @a=count(*) from stuff where id_no='0'select @b=count(*) from stuff where id_no='1'endselect @c=@a+@bselect @d=convert(char(10),@c)print @d
    直接算出果,时间同上面一快!
     
    ---- 总结---- ,所谓优化即where子句利用了索引,不可化即生了表描或开销
    1.任何列的操作都将致表描,它包括数据函数、算表达式等等,查询时要尽可能将操作移至等号右
    2.inor子句常会使用工作表,使索引失效;如果不生大量重复值,可以考把子句拆;拆的子句中应该包含索引。
    3.要善于使用存储过程,它使SQL得更加灵活和高效。
    从以上些例子可以看出,SQL化的实质就是在果正确的前提下,用化器可以识别句,充份利用索引,减少表描的I/O次数,尽量避免表搜索的生。其SQL的性能化是一个复杂程,上述些只是在次的一,深入研究及数据库层源配置、网络层的流量控制以及操作系统层设计
     
    转:http://blog.csdn.net/gprime/article/details/1687930
  • 相关阅读:
    在Centos 7下编译openwrt+njit-client
    开博随笔
    Chapter 6. Statements
    Chapter 4. Arrays and Pointers
    Chapter 3. Library Types
    Chapter 2.  Variables and Basic Types
    关于stm32不常用的中断,如何添加, 比如timer10 timer11等
    keil 报错 expected an identifier
    案例分析 串口的地不要接到电源上 会烧掉
    案例分析 CAN OPEN 调试记录 进度
  • 原文地址:https://www.cnblogs.com/garyxiao/p/2918435.html
Copyright © 2020-2023  润新知