同样的SQL语句,执行效率却不同,执行计划也不同,望高手指点,谢谢

lw8122 2010-04-03 05:15:24
select fID,fName,fuName,
(select sum(sldQuantity) from shopListDetail,shopList,cash where cBusinessDay>='2010-03-01' and cBusinessDay<='2010-03-31' and sld_slID=slID and sl_cID=cID and sldPresent=0 and sldDisposed<>1 and sld_fID=fID) as saleCount ,
(select sum(sldMoney) from shopListDetail,shopList,cash where cBusinessDay>='2010-03-01' and cBusinessDay<='2010-03-31' and sld_slID=slID and sl_cID=cID and sldPresent=0 and sldDisposed<>1 and sld_fID=fID) as saleMoney ,
(select sum(sldQuantity) from shopListDetail,shopList,cash where cBusinessDay>='2010-03-01' and cBusinessDay<='2010-03-31' and sld_slID=slID and sl_cID=cID and sldPresent=1 and sldDisposed<>1 and sld_fID=fID) as presentCount ,
(select sum(sldMoney) from shopListDetail,shopList,cash where cBusinessDay>='2010-03-01' and cBusinessDay<='2010-03-31' and sld_slID=slID and sl_cID=cID and sldPresent=1 and sldDisposed<>1 and sld_fID=fID) as presentMoney ,
f_countftID from food,foodUnit where f_fuID=fuID and
fID in (select Distinct sld_fID from shopListDetail,shopList,cash where cBusinessDay>='2010-03-01' and cBusinessDay<='2010-03-31' and sld_slID=slID and sl_cID=cID )
order by f_countftID,fID

做一个统计,统计的范围,是3月1日,到3月31日,也就是一个月的数据。
执行这条指令,大概要花60秒左右。

cash表记录数为 9676条
shopList表的记录数为 11657条
shopListDetail表的记录数为 18620条
food表,和foodType表,是商品信息,属于基础数据,记录数也就100多条吧。

只要把开始时间,改为1月1日,到3月31日,统计3个月的数据。
涉及到的数据量,cash表,shopList表,shopListDetail的记录数,都应该翻3位左右。
则查询1秒钟之内就完成了。

最终统计的输出结果,都是正确的。

继续做测试,发现一个很奇怪的想象:
1月1日,到1月31日,效率正常。
2月1日,到2月28日,效率正常。
1月1日,到3月31日,效率正常。
2月1日,到3月31日,效率正常。
2月20日,到3月31日,效率正常。
起始日期于2009年,效率都是正常的。
即使是统计2009年1月1日,到2010年3月31日,统计都会在1秒左右完成。

2月25日,到3月31日,效率低下。 (大概60秒)
2月25日,到3月5日,效率低下。 (大概20秒)
3月10日,到3月20日,效率低下。 (大概20秒)

用查询分析器看了执行计划,《效率低下》,和《效率正常》,执行计划里反映的图表,完全不同。
《效率低下》是一种图表。
《效率正常》则是另一种图表。
俺也不懂,怎么把执行计划搞成数据,发到网上来,希望有高手能指点一下。


俺手里有很多客户的数据库,做测试,永远的《效率正常》的情况。即使统计几年的数据,最多也就2、3秒钟
只有这一个客户的数据库,在特定情况下,会出现《效率低下》的情况。

程序已经投入使用几年了,全部正常,只有这个客户这里,出现了异常。 这个客户的数据量,也不是最大的。

目前,对这个客户,只要把command.CommandTimeout,从缺省的30秒,改为600秒(10分钟),就可以了。 这个统计,也不是经常做。
目前,只有对《3月,或是近期数据》进行统计,可能出现《效率低下》的情况。花费1分多钟,总可以统计出来。
但是,很害怕万一出现统计1年数据时,出现《效率低下》的情况,导致一个统计要花费30分钟、甚至30分钟以上。

而且,今天发现了一条SQL语句出现了问题。
天知道还有哪条SQL语句,会在特定的情况下,出现《效率低下》的问题。
总感觉这是一颗不定时炸弹,天知道他在啥地方,在啥时间会爆。

有没有高手能指点一下???如果需要,俺可以把数据库提供出来。
...全文
750 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
lw8122 2010-04-04
  • 打赏
  • 举报
回复
to 6楼的朋友:

刚刚又查了一下。

您提供的方法,似乎只有sql 2005上行得通。
俺的是sql 2000,所以不支持。

但还是谢谢你。
lw8122 2010-04-04
  • 打赏
  • 举报
回复
to 18楼的朋友:

谢谢,你说的方法,也应该可以。
不过,用重建索引命令,应该更科学一些。 引用一段命令介绍:

--------------------------------------------------------------
DBCC DBREINDEX 可以使用一条语句重建表的所有索引,这比对多个 DROP INDEX 和 CREATE INDEX 语句进行编码容易。由于该工作是通过一条语句完成的,所以 DBCC DBREINDEX 自动为原子性,而单个 DROP INDEX 和 CREATE INDEX 语句要成为原子性则必须放在事务中。另外,与使用单个 DROP INDEX 和 CREATE INDEX 语句相比,DBCC DBREINDEX 可从 DBCC DBREINDEX 的优化性能中更多地获益。
--------------------------------------------------------------
lw8122 2010-04-04
  • 打赏
  • 举报
回复
直接执行重建索引命令,问题解决,而且整个检索速度,都有所提高。

DBCC DBREINDEX (shoplist)
DBCC DBREINDEX (shoplistDetail)
DBCC DBREINDEX (cash)

问题已解决。

目前正在研究,如何查询索引碎片的状态。
hfrll 2010-04-04
  • 打赏
  • 举报
回复
..................了解中…………
dawugui 2010-04-03
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 lw8122 的回复:]
引用 13 楼 za363k6 的回复:
先检查索引碎片 然后重建索引..


可否说说,怎么重建索引?? 可否提供一个命令??
[/Quote]
删除索引,然后重新按照原来的方法建立即可.

如果是大数据量,慎重.这些步骤可能会需要很长时间.
lw8122 2010-04-03
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 za363k6 的回复:]
先检查索引碎片 然后重建索引..
[/Quote]

可否说说,怎么重建索引?? 可否提供一个命令??
lw8122 2010-04-03
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 sql77 的回复:]
引用 3 楼 sql77 的回复:

数据量的大小会影响执行计划的
[/Quote]

麻烦的这是这个问题。
统计1个月的数据,居然比统计1年的数据还要慢得多。

而执行计划,是不由我控制的。
也许,在我模拟的测试环境下,效率都是正常的。
但是实际使用中,仅仅是时间范围不同,产生一种偶然情况,导致SQL选用了一种愚蠢的执行计划,导致效率级低。

而且,我没法控制同,SQL选用哪种执行计划。
lg314 2010-04-03
  • 打赏
  • 举报
回复
这个语句太罗嗦了,应该考虑重写一下了。

还有in 里面的查询不用写Distinct

数据库是什么版本的?
lg314 2010-04-03
  • 打赏
  • 举报
回复
如果能服务器能有空闲的时间的话写个脚本把所有的索引删掉后重建
za363k6 2010-04-03
  • 打赏
  • 举报
回复
先检查索引碎片 然后重建索引..
vbyes 2010-04-03
  • 打赏
  • 举报
回复
where f_fuID=fuID and fID in ......

用 where 。。。 in 。。。。语句上会不会慢一点? 我对SQL SERVER 不是太了解,但在其他ACCESS
和VB 结合的地方也做过实例, 我帮他把语句用联接语句替换 where in 速度提高了十多倍,

不过我不敢保证在 SQL SERVER 是否是这样子,算我猜的吧。
SQL77 2010-04-03
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 lw8122 的回复:]
引用 3 楼 sql77 的回复:
表的结构和索引那些都一样吗

清理一下缓存,重建立执行计划和索引试试


同一个数据库,只因统计的时间范围不同,就会产生不同的效率。

《清理一下缓存,重建立执行计划和索引试试》这个如何操作??
[/Quote]
同一个数据库,只因统计的时间范围不同,就会产生不同的效率。

数据量的大小会影响执行计划的
lw8122 2010-04-03
  • 打赏
  • 举报
回复
to fredrickhu(小F) :
---------------------------------------------------
use sygl
go
select
a.index_id,---索引编号
b.name,---索引名称
avg_fragmentation_in_percent---索引的逻辑碎片
from
sys.dm_db_indx_physical_stats(db_id(),object_id(N'create.consume'),null,null,null) as a
join
sys.indexes as b
on
a.object_id=b.object_id
and
a.index_id=b.index_id
go
----------------------------------------------------------------

执行结果为:
-------------------------------------------
服务器: 消息 170,级别 15,状态 1,行 6
第 6 行: '(' 附近有语法错误。
-------------------------------------------
lw8122 2010-04-03
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 sql77 的回复:]
表的结构和索引那些都一样吗

清理一下缓存,重建立执行计划和索引试试
[/Quote]

同一个数据库,只因统计的时间范围不同,就会产生不同的效率。

《清理一下缓存,重建立执行计划和索引试试》这个如何操作??
lw8122 2010-04-03
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 happyflystone 的回复:]
DBCC CHECKTABLE
[/Quote]

DBCC CHECKTABLE ('shoplist')
DBCC CHECKTABLE ('cash')
DBCC CHECKTABLE ('shoplistDetail')
DBCC CHECKTABLE ('food')
DBCC CHECKTABLE ('foodType')

执行结果如下:

'shopList' 的 DBCC 结果。
对象 'shopList' 有 126156 行,这些行位于 1579 页中。
DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。
'Cash' 的 DBCC 结果。
对象 'Cash' 有 103760 行,这些行位于 4724 页中。
DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。
'ShopListDetail' 的 DBCC 结果。
对象 'ShopListDetail' 有 193032 行,这些行位于 1952 页中。
DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。
'Food' 的 DBCC 结果。
对象 'Food' 有 170 行,这些行位于 3 页中。
DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。
'foodType' 的 DBCC 结果。
对象 'foodType' 有 16 行,这些行位于 1 页中。
DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。

执行结束后,问题依旧。
--小F-- 2010-04-03
  • 打赏
  • 举报
回复
先检查索引碎片 然后重建索引..
--小F-- 2010-04-03
  • 打赏
  • 举报
回复
--查询数据库db中表tb的所有索引的随片情况
use db
go
select
a.index_id,---索引编号
b.name,---索引名称
avg_fragmentation_in_percent---索引的逻辑碎片
from
sys.dm_db_indx_physical_stats(db_id(),object_id(N'create.consume'),null,null,null) as a
join
sys.indexes as b
on
a.object_id=b.object_id
and
a.index_id=b.index_id
go

---解释下sys.dm_db_indx_physical_stats的参数
datebase_id: 数据库编号,可以使用db_id()函数获取指定数据库名对应的编号。
object_id: 该索引所属表或试图的编号
index_id: 该索引的编号
partition_number:对象中分区的编号
mode:模式名称,用于指定获取统计信息的扫描级别。


有关sys.dm_db_indx_physical_stats的结果集中的字段名去查下联机丛书。



本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/fredrickhu/archive/2010/01/12/5183068.aspx
yhtapmys 2010-04-03
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 sql77 的回复:]
表的结构和索引那些都一样吗

清理一下缓存,

重建立执行计划和索引试试
[/Quote]

up
Garnett_KG 2010-04-03
  • 打赏
  • 举报
回复
有偿支持
SQL77 2010-04-03
  • 打赏
  • 举报
回复
表的结构和索引那些都一样吗

清理一下缓存,

重建立执行计划和索引试试
加载更多回复(2)

22,210

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧