1

我们有一个查询需要很长时间才能完成一个大型数据集。我想我已经将它追踪到 SQL 服务器中的表值函数。

该查询旨在返回两个日期之间的打印使用差异。因此,如果打印机在日期 x 使用 100,在日期 ya 使用 200,则需要返回行,这反映了它的使用更改为 100。

这些读数会定期(但不是每天)采集并存储在名为 MeterReadings 的表中。表值函数的代码如下。然后从另一个 SQL 查询中调用它,该查询将设备表上的返回表与内部连接连接起来,以获取额外的设备信息。

任何有关如何优化以下内容的建议将不胜感激。

ALTER FUNCTION [dbo].[DeviceUsage]
-- Add the parameters for the stored procedure here
( @StartDate DateTime , @EndDate DateTime )
RETURNS table
AS
RETURN
(

SELECT      MAX(dbo.MeterReadings.ScanDateTime) AS MX,
        MAX(dbo.MeterReadings.DeviceTotal - reading.DeviceTotal) AS TotalDiff, 
        MAX(dbo.MeterReadings.TotalCopy - reading.TotalCopy) AS CopyDiff,
        MAX(dbo.MeterReadings.TotalPrint - reading.TotalPrint) AS PrintDiff,
        MAX(dbo.MeterReadings.TotalScan - reading.TotalScan) AS ScanDiff,
        MAX(dbo.MeterReadings.TotalFax - reading.TotalFax) AS FaxDiff,
        MAX(dbo.MeterReadings.TotalMono - reading.TotalMono) AS MonoDiff,
        MAX(dbo.MeterReadings.TotalColour - reading.TotalColour) AS ColourDiff, 
        MIN(reading.ScanDateTime) AS MN, dbo.MeterReadings.DeviceID

FROM        dbo.MeterReadings INNER JOIN (SELECT * FROM dbo.MeterReadings WHERE     
        (dbo.MeterReadings.ScanDateTime > @StartDate) AND 
        (dbo.MeterReadings.ScanDateTime < @EndDate) ) 
        AS reading ON dbo.MeterReadings.DeviceID = reading.DeviceID

WHERE       (dbo.MeterReadings.ScanDateTime > @StartDate) AND (dbo.MeterReadings.ScanDateTime < @EndDate)

GROUP BY    dbo.MeterReadings.DeviceID);
4

2 回答 2

0

您的查询似乎计算每个特定设备的时间范围内所有读数的叉积。这在语义上有效,因为 MIN 和 MAX 聚合不关心重复。但这非常慢。如果您将 100 个日期与其自身进行比较,则需要处理 10,000 行。

我建议您计算整个时间间隔内每个指标/列的 MIN 和 MAX 值,然后减去它们。这样你就不需要加入,你需要单次传递数据。像这样:

select Diff = MAX(col) - MIN(col)
from readings
group by DeviceID
于 2012-06-14T11:04:25.817 回答
0

假设一个值只能随着时间的推移而增加,它当然可以被简化。

SELECT
  DeviceID,
  MIN(ScanDateTime)                      AS MN,
  MAX(ScanDateTime)                      AS MX,
  MAX(DeviceTotal ) - MIN(DeviceTotal)   AS TotalDiff,
  MAX(TotalCopy   ) - MIN(TotalCopy  )   AS CopyDiff,
  MAX(TotalPrint  ) - MIN(TotalPrint )   AS PrintDiff,
  MAX(TotalScan   ) - MIN(TotalScan  )   AS ScanDiff,
  MAX(TotalFax    ) - MIN(TotalFax   )   AS FaxDiff,
  MAX(TotalMono   ) - MIN(TotalMono  )   AS MonoDiff,
  MAX(TotalColour ) - MIN(TotalColour)   AS ColourDiff
FROM
  dbo.MeterReadings
WHERE
      ScanDateTime > @StartDate
  AND ScanDateTime < @EndDate
GROUP BY
  DeviceID

这假设如果您阅读日期1, 3, 5, 7, 9并且想要报告,2 -> 8那么您想要reading 7- reading 3。我会以为你想要reading 7- reading 1

上述查询对于相对较小的范围应该没问题。如果您的时间范围很大,MAX() - MIN()则将在大量行上运行。然后可以通过以下方式进一步改进这一点(使用相关的子查询来查找您想要的两行)。

作为一个附带的好处,即使值可以上下波动,这也有效。

(我假设存在一个 Device 表以获得更简单的查询和更快的性能。)

SELECT
  Device.DeviceID,
  start.ScanDateTime                      AS MN,
  finish.ScanDateTime                     AS MX,
  finish.DeviceTotal - start.DeviceTotal  AS TotalDiff,
  finish.TotalCopy   - start.TotalCopy    AS CopyDiff,
  finish.TotalPrint  - start.TotalPrint   AS PrintDiff,
  finish.TotalScan   - start.TotalScan    AS ScanDiff,
  finish.TotalFax    - start.TotalFax     AS FaxDiff,
  finish.TotalMono   - start.TotalMono    AS MonoDiff,
  finish.TotalColour - start.TotalColour  AS ColourDiff
FROM
  dbo.Device                 AS device
INNER JOIN
  dbo.MeterReadings          AS start
    ON  start.DeviceID = device.DeviceID
    AND start.ScanDateTime = (SELECT MIN(ScanDateTime)
                                FROM dbo.MeterReadings
                               WHERE DeviceID = device.DeviceID
                                 AND ScanDateTime > @startDate
                                 AND ScanDateTime < @endDate)
INNER JOIN
  dbo.MeterReadings          AS finish
    ON  finish.DeviceID     = device.DeviceID
    AND finish.ScanDateTime = (SELECT MAX(ScanDateTime)
                                FROM dbo.MeterReadings
                               WHERE DeviceID = device.DeviceID
                                 AND ScanDateTime > @startDate
                                 AND ScanDateTime < @endDate)

如果需要,这也可以修改为将开始日期作为@startDate 或之前的第一个日期。

编辑:修改以将开始读数选择为@startDate 上或之前的第一个日期。

SELECT
  Device.DeviceID,
  start.ScanDateTime                                                AS MN,
  finish.ScanDateTime                                               AS MX,
  COALESCE(finish.DeviceTotal, 0) - COALESCE(start.DeviceTotal, 0)  AS TotalDiff,
  COALESCE(finish.TotalCopy  , 0) - COALESCE(start.TotalCopy  , 0)  AS CopyDiff,
  COALESCE(finish.TotalPrint , 0) - COALESCE(start.TotalPrint , 0)  AS PrintDiff,
  COALESCE(finish.TotalScan  , 0) - COALESCE(start.TotalScan  , 0)  AS ScanDiff,
  COALESCE(finish.TotalFax   , 0) - COALESCE(start.TotalFax   , 0)  AS FaxDiff,
  COALESCE(finish.TotalMono  , 0) - COALESCE(start.TotalMono  , 0)  AS MonoDiff,
  COALESCE(finish.TotalColour, 0) - COALESCE(start.TotalColour, 0)  AS ColourDiff
FROM
  dbo.Device                 AS device
LEFT JOIN
  dbo.MeterReadings          AS start
    ON  start.DeviceID = device.DeviceID
    AND start.ScanDateTime = (SELECT MAX(ScanDateTime)
                                FROM dbo.MeterReadings
                               WHERE DeviceID = device.DeviceID
                                 AND ScanDateTime < @startDate)
LEFT JOIN
  dbo.MeterReadings          AS finish
    ON  finish.DeviceID     = device.DeviceID
    AND finish.ScanDateTime = (SELECT MAX(ScanDateTime)
                                FROM dbo.MeterReadings
                               WHERE DeviceID = device.DeviceID
                                 AND ScanDateTime < @endDate)
于 2012-06-14T11:19:22.247 回答