如何让你的SQL运行得更快

在使用 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 date28秒)
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 date27秒)
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 date11秒)
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_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 + (外 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< 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. 例:表 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 策略 "
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值