Sql server Microsoft SQL查询优化

Sql server Microsoft SQL查询优化,sql-server,Sql Server,我创建了一段SQL,使用游标从表中获取一些值,但是它的效率非常低,执行起来需要相当长的时间。我需要使用SSRS烛台图的结果,所以我需要收集最小值、最大值以及打开和关闭值,但是我不太熟悉SQL,需要进行优化。表中的数据每5分钟获得一个新的时间戳和管道计数。以下是我目前掌握的代码: declare @min int, @max int, @open int, @close int, @date date create table ##Candle ( MinVal int, Max

我创建了一段SQL,使用游标从表中获取一些值,但是它的效率非常低,执行起来需要相当长的时间。我需要使用SSRS烛台图的结果,所以我需要收集最小值、最大值以及打开和关闭值,但是我不太熟悉SQL,需要进行优化。表中的数据每5分钟获得一个新的时间戳和管道计数。以下是我目前掌握的代码:

declare
@min int,
@max int,
@open int,
@close int,
@date date

create table ##Candle
(
    MinVal int,
    MaxVal int,
    OpenVal int,
    CloseVal int,
    CalDate date
)

DECLARE C1 CURSOR LOCAL FOR SELECT CONVERT(date,TimeCollected) as CalendarDate from data.PipelineCount where TimeCollected > dateadd(mm,-1,CONVERT(date,GETDATE())) order by CalendarDate;
OPEN C1;
FETCH NEXT FROM C1 INTO @date;

WHILE @@FETCH_STATUS = 0
BEGIN
    select
    @min = min(PipelineCount),
    @max = max(PipelineCount)
    from data.PipelineCount
    where convert(date,TimeCollected) = @date;

    select top 1
    @open = PipelineCount
    from data.PipelineCount
    where convert(date,TimeCollected) = @date and datepart(hour,TimeCollected) = 8;

    select top 1
    @close = PipelineCount
    from data.PipelineCount
    where convert(date,TimeCollected) = @date and datepart(hour,TimeCollected) = 17;

    insert into ##Candle values(@min,@max,@open,@close,@date);
FETCH NEXT FROM C1 INTO @date;
END
CLOSE C1;
DEALLOCATE C1;

有人有什么想法可以帮忙吗?

基本的查询性能问题在于WHERE子句

where convert(date,TimeCollected) = @date
您希望该子句能够在表中的TimeCollected列上使用索引。试着这样做:

where TimeCollected >= @date
  and TimeCollected < DATEADD(DAY, 1, @date)
其中TimeCollected>=@date
和收集的时间<日期添加(天,1,@date)
为什么这样更好?当您对where子句中的列应用函数时,服务器必须在所谓的全表扫描中查看每一行,以查看其是否匹配。我建议重构where子句,让服务器对索引进行范围扫描,这样它可以查看更少的行。在本例中,它只查看@date和一天后之间的行

恕我直言,我不理解您示例查询中的逻辑,因此无法为您重构整个过程。但是,正如我所建议的,将where子句设置为“sargable”将有很大帮助。读这个


顺便说一下,如果在SSMS的查询面板中单击鼠标右键,可以选中一个选项,询问“实际查询计划”。看看这一点可以告诉你很多为什么你的查询很慢。如果需要,它甚至会推荐索引。

基本的查询性能问题在于WHERE子句

where convert(date,TimeCollected) = @date
您希望该子句能够在表中的TimeCollected列上使用索引。试着这样做:

where TimeCollected >= @date
  and TimeCollected < DATEADD(DAY, 1, @date)
其中TimeCollected>=@date
和收集的时间<日期添加(天,1,@date)
为什么这样更好?当您对where子句中的列应用函数时,服务器必须在所谓的全表扫描中查看每一行,以查看其是否匹配。我建议重构where子句,让服务器对索引进行范围扫描,这样它可以查看更少的行。在本例中,它只查看@date和一天后之间的行

恕我直言,我不理解您示例查询中的逻辑,因此无法为您重构整个过程。但是,正如我所建议的,将where子句设置为“sargable”将有很大帮助。读这个


顺便说一下,如果在SSMS的查询面板中单击鼠标右键,可以选中一个选项,询问“实际查询计划”。看看这一点可以告诉你很多为什么你的查询很慢。如果需要,它甚至会推荐索引。

是。停止使用光标像这样插入。只需创建一个select语句即可获得所需的行。而且也不要使用全局临时表,它们充满了并发性问题。嗯,从上午8:00到上午8:59:59,您只有一个价格?这似乎不正确。开盘价不是给定日期的第一个(按时间计算)价格吗?我尝试了几种不同的方法来获取数据,我可以通过其他选择来获取最小值和最大值,但我还没有找到一种方法来只为每个时间要求返回一个计数。@SMor每5分钟有一个新条目,开放时间是第8小时,关闭时间是第17小时,从小时中选择top 1将始终返回该小时的第一个条目是?否-使用top时没有order by子句。在轻负荷条件下,这可能会给你你想要的东西,但不能保证你也假设在这段时间内至少存在一个价格。也许这是典型的——但要注意你的假设。如果不存在这样的价格,猜猜会发生什么?上一次循环迭代的值保留在变量中。这就是使用select指定标量变量的危险。是。停止使用光标像这样插入。只需创建一个select语句即可获得所需的行。而且也不要使用全局临时表,它们充满了并发性问题。嗯,从上午8:00到上午8:59:59,您只有一个价格?这似乎不正确。开盘价不是给定日期的第一个(按时间计算)价格吗?我尝试了几种不同的方法来获取数据,我可以通过其他选择来获取最小值和最大值,但我还没有找到一种方法来只为每个时间要求返回一个计数。@SMor每5分钟有一个新条目,开放时间是第8小时,关闭时间是第17小时,从小时中选择top 1将始终返回该小时的第一个条目是?否-使用top时没有order by子句。在轻负荷条件下,这可能会给你你想要的东西,但不能保证你也假设在这段时间内至少存在一个价格。也许这是典型的——但要注意你的假设。如果不存在这样的价格,猜猜会发生什么?上一次循环迭代的值保留在变量中。这就是使用select分配标量变量的危险。我尝试的是检索PipelineCount的最小值、最大值、开始值(第8小时的值)和结束值(第17小时的值)。这个数据库中存储的是一个int记录编号(主键),TimeCollected作为datetime,PipelineCount作为int。我无法在select语句中找到一种方法来实现这一点,所以我创建了一个游标,每天迭代并获取这些值。非常感谢您的输入,我将进行此更改并查看它对我的查询的影响。我尝试的是检索PipelineCount的最小值、最大值、开始值(第8小时的值)和结束值(第17小时的值)。这个数据库中存储的是一个int记录编号(主键),TimeCollected作为datetime,PipelineCount作为int。我无法在select语句中找到一种方法来实现这一点,所以我创建了一个游标来每天迭代并获取这些值