在SQL Server中优化ROW_NUMBER()

Blu*_*eft 6 t-sql sql-server optimization sql-server-2005 query-optimization

我们有许多机器以零星的间隔将数据记录到数据库中.对于每条记录,我想获得录制和上一次录制之间的时间段.

我可以使用ROW_NUMBER执行此操作,如下所示:

WITH TempTable AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY Machine_ID ORDER BY Date_Time) AS Ordering
    FROM dbo.DataTable
)

SELECT [Current].*, Previous.Date_Time AS PreviousDateTime
FROM TempTable AS [Current]
INNER JOIN TempTable AS Previous 
    ON [Current].Machine_ID = Previous.Machine_ID
    AND Previous.Ordering = [Current].Ordering + 1
Run Code Online (Sandbox Code Playgroud)

问题是,它真的很慢(在一个有大约10k条目的表上几分钟) - 我尝试在Machine_ID和Date_Time上创建单独的指示,以及一个连接索引,但没有任何帮助.

无论如何重写此查询以更快?

Rem*_*anu 7

给定的ROW_NUMBER()分区和顺序要求索引(Machine_ID, Date_Time)在一次传递中满足:

CREATE INDEX idxMachineIDDateTime ON DataTable (Machine_ID, Date_Time);
Run Code Online (Sandbox Code Playgroud)

如果有的话,Machine_ID和Date_Time上的单独索引将帮助很少.

  • 那是因为你的*触发了索引引爆点.将其限制为仅需要的列,并使用包括使非聚集索引覆盖.如果需要太多列,则必须将其更改为聚簇索引,并产生所有后果. (4认同)

Cad*_*oux 6

它与这个版本相比如何?:

SELECT x.*
    ,(SELECT MAX(Date_Time)
      FROM dbo.DataTable
      WHERE Machine_ID = x.Machine_ID
          AND Date_Time < x.Date_Time
    ) AS PreviousDateTime
FROM dbo.DataTable AS x
Run Code Online (Sandbox Code Playgroud)

还是这个版本?:

SELECT x.*
    ,triang_join.PreviousDateTime
FROM dbo.DataTable AS x
INNER JOIN (
    SELECT l.Machine_ID, l.Date_Time, MAX(r.Date_Time) AS PreviousDateTime
    FROM dbo.DataTable AS l
    LEFT JOIN dbo.DataTable AS r
    ON l.Machine_ID = r.Machine_ID
        AND l.Date_Time > r.Date_Time
    GROUP BY l.Machine_ID, l.Date_Time
) AS triang_join
ON triang_join.Machine_ID = x.Machine_ID
    AND triang_join.Date_Time = x.Date_Time
Run Code Online (Sandbox Code Playgroud)

两者都可以通过Machine_ID,Date_Time上的索引表现最佳,并且对于正确的结果,我假设这是唯一的.

你没有提到隐藏在*中的东西,有时候意味着很多,因为Machine_ID,Date_Time索引通常不会覆盖,如果你有很多列,或者他们有很多数据,...