博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何让你的SQL运行得更快
阅读量:6380 次
发布时间:2019-06-23

本文共 5381 字,大约阅读时间需要 17 分钟。

在使用
SQL
往往会陷入一个
区,即太
注于所得的
果是否正确,而忽略了不同的
实现
方法之
可能存在的性能差异,
这种
性能差异在大型的或是
复杂
的数据
库环
境中(如
机事
务处
OLTP
或决策支持系
DSS
)中表
得尤
笔者在工作
践中
发现
,不良的
SQL
往往来自于不恰当的索引
设计
、不充份的
接条件和不可
化的
where
子句。
们进
行适当的
化后,其运行速度有了明
地提高!
下面我将从
三个方面分
别进
总结
了更直
问题
,所有
例中的
SQL
运行
时间
经过测试
,不超
1秒的均表示
< 1
秒)。
----
测试环
:
主机:
HP LH II----
330MHZ----
内存:
128
----
操作系
Operserver5.0.4----
数据
Sybase11.0.3
 
一、不合理的索引
设计
----
例:表
record
620000
行,
看在不同的索引下,下面几个
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 date(28秒)select count(*) from record where date >'19990901' and place in ('BJ','SH')(14秒)

----
分析:
----
在群集索引下,数据在物理上按
序在数据
上,重
复值
也排列在一起,因而在范
围查
,可以先找到
个范
的起末点,且只在
个范
描数据
,避免了大范
围扫
描,提高了
查询
速度。
---- 3.
place
date
amount
上的
合索引
select count(*) from record where date >'19991201' and date < '19991214' and amount >2000 (26秒)select date,sum(amount) from record group by date(27秒)select count(*) from record where date >'19990901' and place in ('BJ, 'SH')(< 1秒)

 


----
分析:
----
是一个不很合理的
合索引,因
它的前
列是
place
,第一和第二条
SQL
没有引用
place
,因此也没有利用上索引;第三个
SQL
使用了
place
,且引用的所有列都包含在
合索引中,形成了索引覆盖,所以它的速度是非常快的。
---- 4.
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
中形成了索引覆盖,因而性能达到了最
---- 5.
总结
----
缺省情况下建立的索引是非群集索引,但有
它并不是最佳的;合理的索引
设计
要建立在
种查询
的分析和
预测
上。
一般来
.
有大量重
复值
、且
常有范
围查询
between, >,<
>=,< =
)和
order by
group by
生的列,可考
建立群集索引;
.
常同
存取多列,且
列都含有重
复值
可考
建立
合索引;
.
合索引要尽量使
关键查询
形成索引覆盖,其前
列一定是使用最
繁的列。
 
二、不充份的
接条件:
例:表
card
7896
行,在
card_no
上有一个非聚集索引,表
account
191122
行,在
account_no
上有一个非聚集索引,
看在不同的表
接条件下,两个
SQL
行情况:
select sum(a.amount) from account a,card b where a.card_no = b.card_no(20秒)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
+
(外
account
191122
*
card
对应
表第一行所要
找的
3
=595907
I/O
在第二个
接条件下,最佳
查询
方案是将
card
作外
表,
account
作内
表,利用
account
上的索引,其
I/O
次数可由以下公式估算
:外
card
上的
1944
+
(外
card
7896
*
account
对应
一行所要
找的
4
= 33528
I/O
,只有充份的
接条件,真正的最佳方案才会被
行。
总结
1.
多表操作在被
实际执
行前,
查询优
化器会根据
接条件,列出几
可能的
接方案并从中找出系
统开销
最小的最佳方案。
接条件要充份考
虑带
有索引的表、行数多的表;内外表的
选择
可由公式:外
表中的匹配行数
*
表中
一次
找的次数确定,乘
最小
最佳方案。
2.
行方案的方法
--
set showplan
on
,打
showplan
选项
,就可以看到
序、使用何
索引的信息;想看更
详细
的信息,需用
sa
角色
dbcc(3604,310,302)
 
三、不可
化的
where
子句
1.
例:下列
SQL
条件
句中的列都建有恰当的索引,但
行速度却非常慢:
select * from record wheresubstring(card_no,1,4)='5378'(13秒)select * from record whereamount/30< 1000(11秒)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.
例:表
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
上的索引;
实际
上(根据
showplan
,
它却采用了
"OR
策略
"
,即先取出
or
子句的行,存入
临时
数据
的工作表中,再建立唯一索引以去掉重
行,最后从
临时
表中
果。因此,
实际过
程没有利用
id_no
上索引,并且完成
时间还
要受
tempdb
数据
性能的影响。
明,表的行数越多,工作表的性能就越差,当
stuff
620000
时间
竟达到
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.in
or
子句常会使用工作表,使索引失效;如果不
生大量重
复值
,可以考
把子句拆
;拆
的子句中
应该
包含索引。
3.
要善于使用存
储过
程,它使
SQL
得更加灵活和高效。
从以上
些例子可以看出,
SQL
化的
实质
就是在
果正确的前提下,用
化器可以
识别
句,充份利用索引,减少表
描的
I/O
次数,尽量避免表搜索的
生。其
SQL
的性能
化是一个
复杂
程,上述
些只是在
次的一
,深入研究
及数据
库层
源配置、网
络层
的流量控制以及操作系
统层
设计

转载于:https://www.cnblogs.com/ShoneH/p/4691735.html

你可能感兴趣的文章
Windows7 Native Boot流程笔记
查看>>
认识CSS3系列--圆角属性border-radius
查看>>
WCF简单教程(10) Ajax调用
查看>>
实验:从命令行接收多个数字并求和
查看>>
DBCC SHRINKFILE 为什么会运行很长时间?
查看>>
Linux系统下常见性能分析工具的使用
查看>>
linux下QOS--理论篇
查看>>
一步一步学Silverlight 2系列(26):基本图形
查看>>
word无所不能之word连接数据库
查看>>
Wijmo 更优美的jQuery UI部件集:客户端更改C1GridView数据源
查看>>
详解 Windows下apache 实现 SSL
查看>>
从产品疑问到态度问题:808.8GB拷问西部数据
查看>>
cocos2d-x学习笔记16:记录存储1:CCUserDefault
查看>>
Windows Server 2012正式版RDS系列⒀
查看>>
infortrend ESDS RAID6 数据恢复过程
查看>>
基于CentOS5.3邮件系统(Windows AD+Slockd+Dspam)整合
查看>>
WPF/E CTP Quick Start - 第七部分:文本(翻译)
查看>>
求助:WPF不明内存泄露原因,头发都白了几根
查看>>
安全筛选器创建与管理
查看>>
将最小特权原则应用到 Windows XP 上的用户帐户
查看>>