是否可以使用多个内部联接重写此SQL查询,以便它执行得更快?

时间:2012-12-04 04:20:21

标签: sql sql-server tsql sql-server-2005

我有一张200,000行的表。我创建了一个View,我根据不同的标准从这个表中删除数据片段,这些标准符合我对重复记录构成的定义。我有下面这样做的代码,我想知道是否有人可以建议更快/更有效的方法来编写这个查询。它目前需要大约20秒才能执行,但我希望最多可以在几秒钟内执行此查询,如果不是更少的话。我正在使用SQL Server 2005.我对SQL的了解非常初学,我很感激任何帮助。

WITH dsm_hardware_basic_cte AS
(
 SELECT    TOP 100 PERCENT
           dbo.dsm_hardware_basic.[UUID]
          ,dbo.dsm_hardware_basic.[Name]
          ,dbo.dsm_hardware_basic.[LastAgentExecution]
          ,dbo.dsm_hardware_basic.[MaxUserRegistration]
          ,REPLACE(RIGHT([MaxUserRegistration], CHARINDEX('/', REVERSE([MaxUserRegistration])) - 1),'_ADMIN','') AS [MaxUserUsername]
          ,dbo.dsm_hardware_basic.[LastUserRegistration]
          ,REPLACE(RIGHT([LastUserRegistration], CHARINDEX('/', REVERSE([LastUserRegistration])) - 1),'_ADMIN','') AS [LastUserUsername]
          ,dbo.dsm_hardware_basic.[IPAddress]
          ,dbo.dsm_hardware_basic.[HostName]
          ,dbo.dsm_hardware_basic.[MACAddress]
 FROM      dbo.dsm_hardware_basic
)

SELECT     TOP 100 PERCENT
           dsm_hardware_basic_cte.[UUID]
          ,dsm_hardware_basic_cte.[Name]
          ,dsm_hardware_basic_cte.[LastAgentExecution]
          ,dsm_hardware_basic_cte.[MaxUserRegistration]
          ,dsm_hardware_basic_cte.[LastUserRegistration]
          ,dsm_hardware_basic_cte.[IPAddress]
          ,dsm_hardware_basic_cte.[HostName]
          ,dsm_hardware_basic_cte.[MACAddress]
FROM       dsm_hardware_basic_cte
           INNER JOIN
           (
            SELECT    [UUID]
                     ,ROW_NUMBER() OVER (PARTITION BY [Name], [MACAddress] ORDER BY [LastAgentExecution] DESC) AS [NameMACRowNum]
            FROM      dsm_hardware_basic_cte
           ) AS duplicate_NameMAC_filtered
             ON duplicate_NameMAC_filtered.[UUID] = dsm_hardware_basic_cte.[UUID]
            AND duplicate_NameMAC_filtered.[NameMACRowNum] = 1
           INNER JOIN
           (
            SELECT    [UUID]
                     ,ROW_NUMBER() OVER (PARTITION BY [Name], [HostName] ORDER BY [LastAgentExecution] DESC) AS [NameHostNameRowNum]
            FROM      dsm_hardware_basic_cte
           ) AS duplicate_NameHostName_filtered
             ON duplicate_NameHostName_filtered.[UUID] = dsm_hardware_basic_cte.[UUID]
            AND duplicate_NameHostName_filtered.[NameHostNameRowNum] = 1
           INNER JOIN
           (
            SELECT    [UUID]
                     ,ROW_NUMBER() OVER (PARTITION BY [HostName], [MACAddress] ORDER BY [LastAgentExecution] DESC) AS [HostNameMACRowNum]
            FROM      dsm_hardware_basic_cte
           ) AS duplicate_HostNameMAC_filtered
             ON duplicate_HostNameMAC_filtered.[UUID] = dsm_hardware_basic_cte.[UUID]
            AND duplicate_HostNameMAC_filtered.[HostNameMACRowNum] = 1
           INNER JOIN
           (
            SELECT    [UUID]
                     ,ROW_NUMBER() OVER (PARTITION BY [HostName], [IPAddress] ORDER BY [LastAgentExecution] DESC) AS [HostNameIPAddressRowNum]
            FROM      dsm_hardware_basic_cte
           ) AS duplicate_HostNameIPAddress_filtered
             ON duplicate_HostNameIPAddress_filtered.[UUID] = dsm_hardware_basic_cte.[UUID]
            AND duplicate_HostNameIPAddress_filtered.[HostNameIPAddressRowNum] = 1
           INNER JOIN
           (
            SELECT    [UUID]
                     ,ROW_NUMBER() OVER (PARTITION BY [Name], [MaxUserUsername] ORDER BY [LastAgentExecution] DESC) AS [NameMaxUserRowNum]
            FROM      dsm_hardware_basic_cte
           ) AS duplicate_NameMaxUser_filtered
             ON duplicate_NameMaxUser_filtered.[UUID] = dsm_hardware_basic_cte.[UUID]
            AND duplicate_NameMaxUser_filtered.[NameMaxUserRowNum] = 1
           INNER JOIN
           (
            SELECT    [UUID]
                     ,ROW_NUMBER() OVER (PARTITION BY [Name], [LastUserUsername] ORDER BY [LastAgentExecution] DESC) AS [NameLastUserRowNum]
            FROM      dsm_hardware_basic_cte
           ) AS duplicate_NameLastUser_filtered
             ON duplicate_NameLastUser_filtered.[UUID] = dsm_hardware_basic_cte.[UUID]
            AND duplicate_NameLastUser_filtered.[NameLastUserRowNum] = 1

3 个答案:

答案 0 :(得分:0)

根据您的查询计划,LastAgentExecution的排序需要19%的时间。首先在此列上创建索引。

但是,如果我是你,我会改变习惯使用“ROW_NUMBER()OVER(PARTITION BY [Name],[MACAddress] ORDER BY [LastAgentExecution] DESC)”语法类型,因为它似乎不是非常有效

答案 1 :(得分:0)

尝试使用像这样的“Exists”子句替换它们而不是内部联接

WHERE      EXISTS           
           ((SELECT [UUID],[NameMACRowNum]
                FROM
                        (SELECT    [UUID]
                                 ,ROW_NUMBER() OVER (PARTITION BY [Name], [MACAddress] ORDER BY [LastAgentExecution] DESC) AS [NameMACRowNum]
                        FROM      dsm_hardware_basic_cte) AS duplicate_NameMAC_filtered
            WHERE duplicate_NameMAC_filtered.[UUID] = dsm_hardware_basic_cte.[UUID]
            AND duplicate_NameMAC_filtered.[NameMACRowNum] = 1)

不确定它应该存在还是不存在,但一旦其余部分正常工作就会很容易改变。

答案 2 :(得分:0)

我不知道你的需求是什么,但我会尝试重写这样的查询:

WITH dsm_hardware_basic_cte AS (
 SELECT
    d.[UUID]
    ,d.[Name]
    ,d.[LastAgentExecution]
    ,d.[MaxUserRegistration]
    ,REPLACE(RIGHT([MaxUserRegistration], CHARINDEX('/', REVERSE([MaxUserRegistration])) - 1),'_ADMIN','') AS [MaxUserUsername]
    ,d.[LastUserRegistration]
    ,REPLACE(RIGHT([LastUserRegistration], CHARINDEX('/', REVERSE([LastUserRegistration])) - 1),'_ADMIN','') AS [LastUserUsername]
    ,d.[IPAddress]
    ,d.[HostName]
    ,d.[MACAddress]
    ,ROW_NUMBER() OVER (PARTITION BY [Name], [MACAddress] ORDER BY [LastAgentExecution] DESC) AS [NameMACRowNum]
    ,ROW_NUMBER() OVER (PARTITION BY [Name], [HostName] ORDER BY [LastAgentExecution] DESC) AS [NameHostNameRowNum]
    ,ROW_NUMBER() OVER (PARTITION BY [HostName], [MACAddress] ORDER BY [LastAgentExecution] DESC) AS [HostNameMACRowNum]
    ,ROW_NUMBER() OVER (PARTITION BY [HostName], [IPAddress] ORDER BY [LastAgentExecution] DESC) AS [HostNameIPAddressRowNum]
    ,ROW_NUMBER() OVER (PARTITION BY [Name], [MaxUserUsername] ORDER BY [LastAgentExecution] DESC) AS [NameMaxUserRowNum]
    ,ROW_NUMBER() OVER (PARTITION BY [Name], [LastUserUsername] ORDER BY [LastAgentExecution] DESC) AS [NameLastUserRowNum]
 FROM      dbo.dsm_hardware_basic as d
)

SELECT
    c.[UUID]
    ,c.[Name]
    ,c.[LastAgentExecution]
    ,c.[MaxUserRegistration]
    ,c.[LastUserRegistration]
    ,c.[IPAddress]
    ,c.[HostName]
    ,c.[MACAddress]
FROM       dsm_hardware_basic_cte as c
WHERE
    c.[NameMACRowNum] = 1
    or c.[NameHostNameRowNum] = 1
    or c.[HostNameMACRowNum] = 1
    or [HostNameIPAddressRowNum] = 1
    or [NameMaxUserRowNum] = 1
    or [NameLastUserRowNum] = 1

我认为你的查询和我的查询在逻辑上是等价的。优化器可能足够聪明,可以将查询减少到我的查询,但是给它一个旋转,看看!几个笔记:

  1. 我使用表别名以使其更具可读性(在我看来)
  2. 我从您的选择中删除了“前100%”条款。这不是必需的;这通常是人们实施的黑客行为,因此他们可以在视图中执行订单,以获得“有序视图”。不要那样做。 :)