0

我有两个数据库。一个是带有修订号和日期的颠覆日志,另一个包含修订期间更改的修订号和路径。我的查询每月查找最承诺的目录。问题是它需要几分钟才能运行。谁能帮我优化这个野兽般的查询?我确信有更好的方法来做到这一点。

SELECT   [Directory]
    ,[Month]
    ,COUNT([PathMonth]) OVER (PARTITION BY [PathMonth]) AS [Count] INTO ##temp
FROM
    (SELECT  [Path]
            ,[Month]
            ,[Directory]
            ,[Directory] + [Month] AS [PathMonth]
        FROM
            (SELECT [Path]
                    ,SUBSTRING([Path], 0, LEN([Path]) - CHARINDEX('/', REVERSE([Path])) + 1) AS [Directory]
                    ,CONVERT(CHAR(4), [LogDate], 120) + '-' + CONVERT(CHAR(2), [LogDate], 110) AS [Month]
            FROM [SubversionLog] JOIN [PathsLog] ON [SubversionLog].[Revision] = [PathsLog].[Revision]
            WHERE [Path] LIKE '/%/%/%/_%'
            ) one) two
    ORDER BY [Month]
SELECT * INTO ##tempTwo
FROM ##temp
GROUP BY [Directory], [Month], [Count]

SELECT    t1.[Directory]
         ,t1.[Month]
         ,t1.[Count]
    FROM ##tempTwo t1 LEFT JOIN ##tempTwo t2 ON t1.[Month] = t2.[Month] AND t1.[Count] < t2.[Count]
    WHERE t2.[Count] IS NULL
    GROUP BY t1.[Directory], t1.[Month], t1.[Count]
    ORDER BY [Month] DESC


IF EXISTS (SELECT * FROM ##temp)
    DROP TABLE ##temp

IF EXISTS (SELECT * FROM ##tempTwo)
    DROP TABLE ##tempTwo

这项工作的一半是将 YYYY-MM-DD HH:MM:SS.SSS 时间戳格式化为 YYYY-MM 并将文件名路径转换为目录。

4

1 回答 1

1

由于这是您的版本控制,我猜您的表中可能没有超过几十万行。遍历这两个表不会是世界末日,但就像 Peter Schott 所说,这将是一个很好的索引修订:

CREATE nonclustered index <name> on SubversionLog (revision)
CREATE nonclustered index <name> on PathsLog (revision)

从个人经验来看,我不认为做一些字符串操作会严重减慢你的速度。我确实认为创建多个临时表会减慢您的速度,因为您正在为原始表中的大多数行创建一个新行,并且您的临时表没有被索引。因此,我建议摆脱那些临时表,并简化您的查询:

;with filteredData as (
    SELECT [path], 
           Substring([path], 0, Len([path]) - Charindex('/', 
                                              Reverse([path])) + 1) 
                   AS 
           [Directory], 
           CONVERT(CHAR(4), [logdate], 120) + '-' 
           + CONVERT(CHAR(2), [logdate], 110) 
                   AS [Month] 
    FROM   [subversionlog] 
           JOIN [pathslog] 
             ON [subversionlog].[revision] = [pathslog].[revision] 
    WHERE  [path] LIKE '/%/%/%/_%'
), countRevisions as (
    SELECT [month], 
           [directory], 
           count(*) as [Count]
    FROM filteredData
    GROUP BY [MONTH], [directory]
), rankDirectories as (
    SELECT *, RANK() over (partition by month order by count desc) as [Rank]
    from countRevisions
)
select [month], [directory], [count]
from rankDirectories
WHERE [rank] = 1

编辑:

如果不缓存一些结果,我认为您无能为力。您应该查看查询计划以了解需要优化的内容。我猜它在分组、排序和/或排名中,可能是加入或键查找。对于键查找和连接,您可以创建覆盖索引。对于其他内容,您需要缓存结果。我不会缓存一个真实的表,因为这意味着需要一个额外的表来保持最新。相反,我会使用物化视图,以便 SQL Server 为您保持更新。当然这意味着更新会更慢,但是每分钟更新几次(对于源代码控制日志),我认为这不会是一个大问题。

于 2013-06-21T00:07:02.370 回答