SQL Server 2014突然减速/无插入/与硬件或索引无关


8

我正在350GBPC上运行约4000万行的数据库。

SQL服务器2014年,Win7的,AMD 8350 @ 4.8GHZ,16 GB的RAM和500 GB SSD(数据库托管在它自己的500 GB SSD,有一个吞吐量500MB / 500MB的读/写)。

数据库未更新,我只是在分析/读取它。与创建几个indexes,任何joincount(*)等等,只需要不到1分钟,这是确定我的目的。我一直在对数据运行一些查询(运行单个联接查询40-50次后,它变慢了),现在花了1分钟的调用仍在20分钟后运行。

我会密切注意系统资源,SSD当查询开始时我会看到踢进来,它读取20-30秒,然后121kB/second在接下来的20分钟读取。这不是CPU问题或磁盘问题。我的RAM数量有限,但是当我第一次加载数据库时,调用运行良好,现在,25分钟后没有任何运行。

实际上,我再也无法查询数据库,即使是一条基本SELECT语句,任何调用也要花费很长时间。我尝试重建索引并更新统计信息,但没有区别。

我对此没有很多经验,所以我的SQL查询很可能是不正确的,在这种情况下,我期望出现错误,或者它会以0个结果完成执行,但是都不会发生。

我想做的是在基于表ACALLS的时间之前的5秒钟内计数“ TypeID”的所有实例。

SELECT ACALLS.StartTime, ACALLS.Time, ACALLS.ServerIP, ACALLS.SRVR,   ACALLS.calls, ACALLS.TOKEN, COUNT(TypeID) as ExecRate
FROM ACALLS
INNER JOIN MAINVIEW ON 
MainView.TimeStamp BETWEEN ACALLS.StartTime and DATEADD(ss,-5,ACALLS.StartTime)

WHERE DATEPART(hour,MainView.TimeStamp) BETWEEN 10 and 13 and 
CAST(MainView.TimeStamp as date) = '2015-12-09' and
MainView.TypeID = '123456789'
GROUP BY Acalls.STartTime, ACALLs.TIME, ServerIp,SRVR, ACALLS.CALLS, ACALLS.TOKEN
ORDER BY Acalls.StartTime

在运行“谁正在运行”之后, 在此处输入图片说明 在此处输入图片说明


我怀疑这与表上的统计信息以及为联接执行的处理类型有关。您应该查看查询的执行计划:嵌套循环联接可能是问题的征兆。
Gordon Linoff '02

您是否尝试过RECOMPILE?

3
发布出惊人的慢查询的实际执行计划。查询越简单越好。
usr

1
您是否更新了所有表的统计信息?是否重建了所有索引?有关sp_whoisactive以下信息:链接
TT。

2
这些等待状态显示大量的IO,但我们不知道查询中有IO的比例是多少,CPU是什么。执行我建议的测试结果。
usr

Answers:


2

您有一个非SARGable查询-即使您有良好的索引,也不会在该查询中使用它们。

首先,对pageiolatch_sh的下意识反应是将页面从磁盘读取到缓冲区中;您没有足够的RAM来存储要提取的数据。

其次,您需要查看执行计划及其索引的使用-或缺少索引。

退出联接和WHERE中的函数,仅获取绝对需要的数据。

  • “ BETWEEN ACALLS.StartTime和DATEADD(ss,-5,ACALLS.StartTime)”-在BETWEEN中删除该DATEADD。

    • 如果这是一个只读的报告数据库,则仅使用所需数据创建一个报告表,然后根据需要在其上放置复合索引。使用那个来获取所需的ACALLS行的主键/其他唯一键,然后在以后获取其余的ACALLS数据。
  • DATEPART(hour,MainView.TimeStamp)在10和13之间以及CAST(MainView.TimeStamp作为日期)='2015-12-09'

    • 同样的事情-摆脱CAST-将'2015-12-09'更改为MainView.TimeStamp> = @StartTimestamp AND MainView.TimeStamp <@EndTimestamp正确数据类型的一两个@parameters

    • 并通过限制@StartTimestamp和@EndTimestamp使其包含小时数标准来摆脱该DATEPART。

也许在连接之前仅使用满足那些MainView条件的行的主键/唯一键加载#temp表。

嗯...此外,如果Mainview是一个复杂的视图,请直接转到基本表以加载该#temp表

不要忘记使用Profiler来检查并查看在#temp或其他登台表上添加索引(如果需要,可以进行复合)是净收益还是净损失:)。


1

在mainview(typeid,timestamp)上创建一个复合的非聚集索引。

更改主视图上的“位置”,以免对主视图列使用函数。如果需要使这些值更具动态性,则可能需要在运行查询之前将这些值作为变量预先计算。

WHERE MainView.TimeStamp BETWEEN '2015-12-09 10:00' and '2015-12-09 13:00'

在ACALLS.StartTime上创建一个非聚集索引。

将加入到ACALLS的更改为

WHERE ACALLS.StartTime BETWEEN DATEADD(ss,-5,MainView.TimeStamp) AND MainView.TimeStamp

据我了解,这将处理您的逻辑并以相当高的性能加入,使您远离IO。

关于您遇到的问题,我最好的猜测是您的数据正在从缓存中刷新和/或tempdb时不时地溢出到磁盘上,因此,我通常发现的最佳解决方案是更好地编写查询限制了tempdb和内存的使用,根本的问题就消失了。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.