Sql server SQL Server查询执行时间长

Sql server SQL Server查询执行时间长,sql-server,Sql Server,我有以下问题。当前执行5838行的结果需要5.5小时。如果我移除时间戳限制器,并根据视图的所有结果运行它,整个过程将在不到2分钟的时间内运行 当我试图限制时间/日期范围时,我正在寻找一种方法来加快执行速度,并愿意接受任何建议。如果需要,我可以更详细地介绍数据集 SELECT m.rpp ,m.SourceName ,m.ckt AS l_ckt ,m.amp AS l_amp ,MAX(m.reading) AS l_reading ,k.ckt

我有以下问题。当前执行5838行的结果需要5.5小时。如果我移除时间戳限制器,并根据视图的所有结果运行它,整个过程将在不到2分钟的时间内运行

当我试图限制时间/日期范围时,我正在寻找一种方法来加快执行速度,并愿意接受任何建议。如果需要,我可以更详细地介绍数据集

SELECT
    m.rpp
    ,m.SourceName
    ,m.ckt AS l_ckt
    ,m.amp AS l_amp 
    ,MAX(m.reading) AS l_reading
    ,k.ckt AS r_ckt
    ,k.amp AS r_amp
    ,MAX(k.reading) AS r_reading
FROM 
    vRPPPanelLeft m 
INNER JOIN 
    vRPPPanelRight k ON (m.sourcename = k.sourcename) 
                     AND (CAST(m.ckt AS int) + 1 = CAST(k.ckt AS int))
WHERE
    m.timestampserverlocal BETWEEN '2020-10-10' AND '2020-10-12' 
    AND k.timestampserverlocal BETWEEN '2020-10-10' AND '2020-10-11'
GROUP BY
    m.rpp, m.sourcename, m.ckt, m.amp, k.ckt, k.amp

我假设m和k是视图,可能相当复杂,并且/或者有GROUP BY语句

我猜,当您查看执行计划和/或统计数据时,它实际上会多次运行至少一个视图,例如,另一个视图中的每行一个视图

快速修复

如果您能够(例如,它位于存储过程中),我建议执行以下过程

  • 使用与m和k相同的结构(或为此目的使用相关列)创建临时表。包括ckt修改版本的列(例如,两者的ints)。考虑两个临时表的源代码和CKT(INT)的PK(或至少聚集索引),它可能有帮助,也可能不会。
  • 独立运行m和k视图,将结果存储在这些临时表中。使用筛选(例如,timestampserverlocal上的WHERE子句)和可能的相关GROUP BY子句来减少创建的行数
  • 运行原始SQL,但使用临时表而不是视图,并且不需要WHERE子句。它可能仍然需要分组
更长的修复时间

我建议首先进行快速修复,以确认多次运行的视图是问题所在


如果是这样的话(问题是视图被多次运行),一个较长的修复方法是停止使用from中的视图,而是将所有视图放在一个查询中,然后尝试简化代码。

铸造
ckt
列会破坏在这些列上使用任何索引的机会,这些索引可能会有所帮助。如果您可以首先存储它们和
int
值,这可能会带来数量级的改进。此外,如果在时间戳列上添加条件,则当事情变得缓慢时,我们需要知道这些列的确切数据类型。视图从另一个表中的nvarchar字段创建ckt列,因此我不确定是否可以将其设置为int。时间戳列只是一个日期数据类型。您需要检查执行计划,以找出时间花在何处以及如何加快时间。如果您加入视图这可能会导致性能不佳。我经常发现,针对基表编写正确的查询将显著提高性能,这通常是您需要做的第一件也是唯一一件事。我还将考虑将CAST条件迁移到WHERE子句,以便至少联接本身可以使用索引。为视图/表/索引和查询计划提供架构将有助于社区提供一个合理的答案。目前,这两个视图是使用另一个视图中的信息创建的,并且其中一列上包含Max,因此群集索引不是一个选项。每晚通过快照复制从另一个数据库重新创建此数据库。我在看你建议的夜间存储过程,将这两个视图添加到一个表中,以帮助确定执行时间。我的意思是(作为脚本/存储过程等的一部分)使用命令创建带有主键的临时表。语法类似于
CREATE TABLE#vRPPPanelLeft(sourcename nvarchar(100)、ckt int、rpp int、amp decimal(10,2)、reading decimal(10,2)、PRIMARY KEY(sourcename,ckt))
。然后插入到该表中,从视图中选择数据,并根据日期使用WHERE子句。想法是a)用临时表替换视图(在这个SQL命令中),b)在创建这些临时表时尽可能高效。另一方面,如果数据一天只更新一次,并且一天中在报告中多次使用,那么将这些数据预计算到实际表中可能是有意义的(而不是临时表)以帮助报告。如果是这种情况,则只运行原始查询(不带WHERE子句的2分钟版本)可能是有意义的因此,所有数据都已准备好,不需要进行任何实际处理。这可能取决于视图在其他地方的使用频率。感谢您的建议。我创建了一个作业,该作业在夜间数据库复制到此sql实例后运行。它截断了一些表,并将来自视图的结果填充到这些表中。它减少了执行时间从5.5小时降至5秒