`

DB 常用

阅读更多

NVL(expr1,expr2)
如果expr1是NULL,则返回expr2,否则返回expr1.返回值与expr1类型相同,除非expr1是字符串类,在这种情况下将返回VARCHAR2类型.这个函数用于确保查询记录集中不包含NULL值.

类似的还有
NVL(expr1,expr2,expr3)
如果expr1是NULL,则返回expr2,否则返回expr3.返回值与expr2类型相同,除非expr2是字符类型,在这种情况下返回VARCHAR2类型

NULLIF(a,b)
如果a等于b返回NULL,如果不等于返回b.

 

http://vongates.itpub.net/post/2553/17290

 

行转换成列:

 

SELECT a ,WMSYS.WM_CONCAT(b)
FROM tab1
GROUP BY  a;

 

 

 

 

让MYSQL不区分表名大小写的方法其实很简单:

  1.用ROOT登录,修改/etc/my.cnf

  2.在[mysqld]下加入一行:lower_case_table_names=1

  3.重新启动数据库即可。

    重启mysql: /etc/init.d/mysql restart

 

 

  编写优化的SQL语句,充分利用索引

下面就某些SQL语句的where子句编写中需要注意的问题作详细介绍。在这些where子句中,即使某些列存在索引,但是由于编写了劣质的SQL,系统在运行该SQL语句时也不能使用该索引,而同样使用全表扫描,这就造成了响应速度的极大降低。

SQL语句在提交给数据库进行操作前,都会经过查询分析阶段,SQLSERVER内置的查询优化器会分析查询条件的的每个部分,并判断这些条件是否符合扫描参数(SARG)的标准。只有当一个查询条件符合SARG的标准,才可以通过预先设置的索引,提升查询性能。

SARG的定义:用于限制搜索操作的一种规范,通常是指一个特定的匹配,一个确定范围内的匹配或者两个以上条件的AND连接。一般形式如下:

列名 操作符 <常数 或 变量>

<常数 或 变量> 操作符 列名

列名可以出现在操作符的一边,而常数或变量出现在操作符的另一边。如:

Name=’张三’

价格>5000

5000<价格

Name=’张三’ and 价格>5000

如果一个表达式不能满足SARG的形式,那它就无法限制搜索的范围了,也就是说SQL SERVER必须对每一行都判断它是否满足Where子句中的所有条件,既进行全表扫描。所以,一个索引对于不满足SARG形式的表达式来说是无用的, 如:当查询条件为“价格*2 >5000”时,就无法利用建立在价格字段上的索引 。

SQLSERVER内置了查询优化器,能将一些条件自动转换为符合SARG标准,如:将“价格*2 >5000” 转换为“价格 >2500/2 ”,以达到可以使用索引的目的,但这种转化不是100%可靠的,有时会有语义上的损失,有时转化不了。如果对“查询优化器”的工作原理不是特别了解,写出的SQL语句可能不会按照您的本意进行查询。所以不能完全依赖查询优化器的优化,建议大家还是利用自己的优化知识,尽可能显式的书写出符合SARG标准的SQL语句,自行确定查询条件的构建方式,这样一方面有利于查询分析器分析最佳索引匹配顺序,另一方面也有利于今后重读代码。

介绍完SARG后,我们再结合一些实际运用中的例子来做进一步的讲解:

1、 Like语句是否属于SARG取决于使用%通配符的样式

如:name like ‘张%’ ,这就属于SARG

而:name like ‘%张’ ,就不属于SARG

通配符%在字符串首字符的使用会导致索引无法使用,虽然实际应用中很难避免这样用,但还是应该对这种现象有所了解,至少知道此种用法性能是很低下的。

2、 “非”操作符不满足SARG形式,使得索引无法使用 

不满足SARG形式的语句最典型的情况就是包括非操作符的语句,如:NOT、!=、<>、!<、!>、NOT EXISTS、NOT IN、NOT LIKE等。

下面是一个NOT子句的例子:

  ... where not (status ='valid') 

  not运算符也隐式的包含在另外一些逻辑运算符中,比如<>运算符。见下例:

  ... where status <>'invalid'; 


  再看下面这个例子:

  select * from employee where salary<>3000; 

  对这个查询,可以改写为不使用not:

  select * from employee where salary<3000 or salary>3000; 


  虽然这两种查询的结果一样,但是第二种查询方案会比第一种查询方案更快些。第二种查询允许对salary列使用索引,而第一种查询则不能使用索引。


3、 函数运算不满足SARG形式,使得索引无法使用

例:下列SQL条件语句中的列都建有恰当的索引,但执行速度却非常慢:

select * from record where substring(card_no,1,4)=′5378′(13秒)

select * from record where amount/30< 1000(11秒)

select * from record where convert(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明显快很多


4、 尽量不要对建立了索引的字段,作任何的直接处理

select * from employs where first_name + last_name ='beill cliton'; 

无法使用索引


改为:

select * from employee where 

first_name = substr('beill cliton',1,instr('beill cliton',' ')-1) 

and

last_name = substr('beill cliton',instr('beill cliton',' ')+1) 

则可以使用索引

5、 不同类型的索引效能是不一样的,应尽可能先使用效能高的

比如:数字类型的索引查找效率高于字符串类型,定长字符串char,nchar的索引效率高于变长字符串varchar,nvarchar的索引。

应该将

where username='张三' and age>20

改进为

where age>20 and username='张三'

注意:


此处,SQL的查询分析优化功能可以做到自动重排条件顺序,但还是建议预先手工排列好。



6、 尽量不要使用 is null 与 is not null作为查询条件

  任何包含null值的列都将不会被包含在索引中,如果某列数据中存在空值,那么对该列建立索引的性能提升是值得怀疑的,尤其是将null作为查询条件的一部分时。建议一方面避免使用is null和is not null, 另一方面不要让数据库字段中存在null, 即使没有内容,也应利用缺省值,或者手动的填入一个值,如:’’ 空字符串。


7、 某些情况下IN 的作用与OR 相当 ,且都不能充分利用索引

例:表stuff有200000行,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上的索引;但实际上,它却采用了"OR策略",即先取出满足每个or子句的行,存入临时数据库的工作表中,再建立唯一索引以去掉重复行,最后从这个临时表中计算结果。因此,实际过程没有利用id_no上索引,并且完成时间还要受tempdb数据库性能的影响。 

实践证明,表的行数越多,工作表的性能就越差,当stuff有620000行时,执行时间会非常长!如果确定不同的条件不会产生大量重复值,还不如将or子句分开:

select count(*) from stuff where id_no=′0′ 

select count(*) from stuff where id_no=′1′

得到两个结果,再用union作一次加法合算。因为每句都使用了索引,执行时间会比较短, 

select count(*) from stuff where id_no=′0′ 

union

select count(*) from stuff where id_no=′1′

从实践效果来看,使用union在通常情况下比用or的效率要高的多,而exist关键字和in关键字在用法上类似,性能上也类似,都会产生全表扫描,效率比较低下,根据未经验证的说法,exist可能比in要快些。


8、 使用变通的方法提高查询效率

  like关键字支持通配符匹配,但这种匹配特别耗时。例如:select * from customer where zipcode like “21_ _ _”,即使在zipcode字段上已建立了索引,在这种情况下也可能还是采用全表扫描方式。如果把语句改为:select * from customer where zipcode >“21000”,在执行查询时就会利用索引,大大提高速度。但这种变通是有限制的,不应引起业务意义上的损失,对于邮政编码而言,zipcode like “21_ _ _” 和 zipcode >“21000” 意义是完全一致的。

9、 组合索引的高效使用

假设已在date,place,amount三个字段上建立了组合索引

select count(*) from record 

where date > ′19991201′ and date < ′19991214′ and amount > 2000 

(< 1秒) 


select date,sum(amount) from record group by date 

(11秒) 


select count(*) from record 

where date > ′19990901′ and place in (′BJ′,′SH′)

(< 1秒)

这是一个设置较合理的组合索引。它将date作为前导列,使每个SQL都可以利用索引,并且在第一和第三个SQL中形成了索引覆盖,因而性能达到了最优。如果索引不便于更改,修正SQL中的条件顺序以配合索引顺序也是可行的。

10、 order by按聚集索引列排序效率最高 

排序是较耗时的操作,应尽量简化或避免对大型表进行排序,如缩小排序的列的范围,只在有索引的列上排序等等。

我们来看:(gid是主键,fariqi是聚合索引列)

select top 10000 gid,fariqi,reader,title from tgongwen

用时:196 毫秒。 扫描计数 1,逻辑读 289 次,物理读 1 次,预读 1527 次。

select top 10000 gid,fariqi,reader,title from tgongwen order by gid asc

用时:4720毫秒。 扫描计数 1,逻辑读 41956 次,物理读 0 次,预读 1287 次。

select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc

用时:4736毫秒。 扫描计数 1,逻辑读 55350 次,物理读 10 次,预读 775 次。

select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi asc

用时:173毫秒。 扫描计数 1,逻辑读 290 次,物理读 0 次,预读 0 次。

select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi desc

用时:156毫秒。 扫描计数 1,逻辑读 289 次,物理读 0 次,预读 0 次。

从以上我们可以看出,不排序的速度以及逻辑读次数都是和“order by 聚集索引列” 的速度是相当的,但这些都比“order by 非聚集索引列”的查询速度是快得多的。

同时,按照某个字段进行排序的时候,无论是正序还是倒序,速度是基本相当的。

三、 关于节省数据查询系统开销方面的措施

1、 使用TOP尽量减少取出的数据量

TOP是SQL SERVER中用来提取前几条或前某个百分比数据的关键词。

select top 20 gid,fariqi,reader,title from tgongwen order by gid desc

select top 60 percent gid,fariqi,reader,title from tgongwen order by gid desc

在实际的应用中,应该经常利用top 剔除掉不必要的数据,只保留必须的数据集合。这样不仅可以减少数据库逻辑读的次数,还能避免不必要的内存浪费,对系统性能的提升都是有好处的。


2、 字段提取要按照“需多少、提多少”的原则,避免“select *”

这个举个例子:

select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc

用时:4673毫秒

select top 10000 gid,fariqi,title from tgongwen order by gid desc

用时:1376毫秒

select top 10000 gid,fariqi from tgongwen order by gid desc

用时:80毫秒

由此看来,字段大小越大,数目越多,select所耗费的资源就越多,比如取int类型的字段就会比取char的快很多。我们每少提取一个字段,数据的提取速度就会有相应的提升。提升的幅度根据舍弃的字段的大小来判断。

3、 count(*) 与 count(字段) 方法比较

我们来看一些实验例子(gid为Tgongwen的主键):

select count(*) from Tgongwen

用时:1500毫秒

select count(gid) from Tgongwen 

用时:1483毫秒

select count(fariqi) from Tgongwen

用时:3140毫秒

select count(title) from Tgongwen

用时:52050毫秒

从以上可以看出,用count(*)和用count(主键)的速度是相当的,而count(*)却比其他任何除主键以外的字段汇总速度要快,而且字段越长,汇总速度就越慢。如果用count(*), SQL SERVER会自动查找最小字段来汇总。当然,如果您直接写count(主键)将会来的更直接些。

4、 有嵌套查询时,尽可能在内层过滤掉数据

如果一个列同时在主查询和where子句中出现,很可能当主查询中的列值改变之后,子查询必须重新查询一次。而且查询嵌套层次越多,效率越低,因此应当尽量避免子查询。如果子查询不可避免,那么要在子查询中过滤掉尽可能多的行。 

5、 多表关联查询时,需注意表顺序,并尽可能早的过滤掉数据

在使用Join进行多表关联查询时候,应该使用系统开销最小的方案。连接条件要充份考虑带有索引的表、行数多的表,并注意优化表顺序;说的简单一点,就是尽可能早的将之后要做关联的数据量降下来。

一般情况下,sqlserver 会对表的连接作出自动优化。例如: 

select name,no from A 

join B on A. id=B.id 

join C on C.id=A.id 

where name='wang' 

尽管A表在From中先列出,然后才是B,最后才是C。但sql server可能会首先使用c表。它的选择原则是相对于该查询限制为单行或少数几行,就可以减少在其他表中查找的总数据量。绝大多数情况下,sql server 会作出最优的选择,但如果你发觉某个复杂的联结查询速度比预计的要慢,就可以使用SET FORCEPLAN语句强制sql server按照表出现顺序使用表。如上例加上:SET FORCEPLAN ON…….SET FORCEPLAN OFF 表的执行顺序将会按照你所写的顺序执行。在查询分析器中查看2种执行效率,从而选择表的连接顺序。SET FORCEPLAN的缺点是只能在存储过程中使用。


小结:

? 聚集索引比较宝贵,应该用在查询频率最高的地方;

? 在数据为“既不是绝大多数相同,也不是极少数相同”状态时,

最能发挥聚集索引的潜力;

? 复合索引的设置和使用要注意保持顺序一致;

? 条件子句的表达式最好符合SARG规范,是可利用索引的;

? 任何对列的操作都导致全表扫描,如数据库函数、计算表达式等,

查询时应尽可能将操作移至等号的某一边; 

? 要注意含有null值时,是不能充分利用索引的;

? exist, in、or等子句常会使索引失效;

如果不产生大量重复值,可以考虑把子句拆开,再用union拼合;

? 排序时应充分利用带索引的字段;

? 尽可能早,快的过滤掉无用的数据,只将必须的数据带到后续的操作中去

从前面讲叙的内容可以看出,SQL语句优化的实质就是在结果正确的前提下,用分析优化器可以识别的SARG规范语句,充份利用索引,减少数据的I/O次数,尽量避免全表扫描的发生。

以上内容有些是指导性的理论原则,有些是实际摸索的经验,大家在使用时应灵活处理,根据实际情况,选择合适的方法。本文中列举的实验数据仅作比对用,不具备普遍意义。大家在实际项目中,应充分利用性能监测和分析工具(如SQLSERVER带的相关工具)来检验自己的优化效果。

此外,还有很重要的一点要提醒大家,同样复杂的数据操作,在SQLSERVER数据库级别完成的代价要远远小于在应用端用程序代码完成的代价,所以建议大家全面,深入的学习SQL语法中重要关键字的应用,如:Group By ,Having等,尽量把数据操作任务放在数据库系统中完成 。数据库应用系统的性能优化是一个复杂的过程,上述这些只是在SQL语句层次的一种体现,深入研究还会涉及数据库层的资源配置、网络层的流量控制以及操作系统层的总体设计等等,这些将在以后的文章中详细论述

 


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics