加速此查询多次加入表

时间:2010-06-10 15:30:46

标签: sql sql-server

我有这样的查询(向右剥离)是这样的:

SELECT
    [Person_PrimaryContact].[LegalName],
    [Person_Manager].[LegalName],
    [Person_Owner].[LegalName],
    [Person_ProspectOwner].[LegalName],
    [Person_ProspectBDM].[LegalName],
    [Person_ProspectFE].[LegalName],
    [Person_Signatory].[LegalName] 

FROM [Cache]
   LEFT JOIN [dbo].[Person] AS [Person_Owner] WITH (NOLOCK) 
       ON [Person_Owner].[PersonID] = [Cache].[ClientOwnerID]
   LEFT JOIN [dbo].[Person] AS [Person_Manager] WITH (NOLOCK) 
       ON [Person_Manager].[PersonID] = [Cache].[ClientManagerID]
   LEFT JOIN [dbo].[Person] AS [Person_Signatory] WITH (NOLOCK) 
       ON [Person_Signatory].[PersonID] = [Cache].[ClientSignatoryID]
   LEFT JOIN [dbo].[Person] AS [Person_PrimaryContact] WITH (NOLOCK) 
       ON [Person_PrimaryContact].[PersonID] = [Cache].[PrimaryContactID]
   LEFT JOIN [dbo].[Person] AS [Person_ProspectOwner] WITH (NOLOCK) 
       ON [Person_ProspectOwner].[PersonID] = [Cache].[ProspectOwnerID]
   LEFT JOIN [dbo].[Person] AS [Person_ProspectBDM] WITH (NOLOCK) 
       ON [Person_ProspectBDM].[PersonID] = [Cache].[ProspectBDMID]
   LEFT JOIN [dbo].[Person] AS [Person_ProspectFE] WITH (NOLOCK) 
       ON [Person_ProspectFE].[PersonID] = [Cache].[ProspectFEID]

人是一张巨大的桌子,每个人加入它都会在执行计划中受到重创。

无论如何我可以调整此查询,以便我只链接一次,或者至少让SQL Server只扫描一次吗?

修改

这是计划:

  |--Parallelism(Gather Streams)
       |--Merge Join(Right Outer Join, MERGE:([Person_ProspectFE].[PersonID])=([Cache].[ProspectFEID]), RESIDUAL:([PracticeManagement].[dbo].[Person].[PersonID] as [Person_ProspectFE].[PersonID]=[PracticeManagement].[dbo].[ListCache].[ProspectFEID] as [Cache].[ProspectFEID]))
            |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Person_ProspectFE].[PersonID]), ORDER BY:([Person_ProspectFE].[PersonID] ASC))
            |    |--Clustered Index Scan(OBJECT:([PracticeManagement].[dbo].[Person].[Person_PK] AS [Person_ProspectFE]), ORDERED FORWARD)
            |--Sort(ORDER BY:([Cache].[ProspectFEID] ASC))
                 |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Cache].[ProspectFEID]))
                      |--Merge Join(Right Outer Join, MERGE:([Person_ProspectBDM].[PersonID])=([Cache].[ProspectBDMID]), RESIDUAL:([PracticeManagement].[dbo].[Person].[PersonID] as [Person_ProspectBDM].[PersonID]=[PracticeManagement].[dbo].[ListCache].[ProspectBDMID] as [Cache].[ProspectBDMID]))
                           |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Person_ProspectBDM].[PersonID]), ORDER BY:([Person_ProspectBDM].[PersonID] ASC))
                           |    |--Clustered Index Scan(OBJECT:([PracticeManagement].[dbo].[Person].[Person_PK] AS [Person_ProspectBDM]), ORDERED FORWARD)
                           |--Sort(ORDER BY:([Cache].[ProspectBDMID] ASC))
                                |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Cache].[ProspectBDMID]))
                                     |--Merge Join(Right Outer Join, MERGE:([Person_ProspectOwner].[PersonID])=([Cache].[ProspectOwnerID]), RESIDUAL:([PracticeManagement].[dbo].[Person].[PersonID] as [Person_ProspectOwner].[PersonID]=[PracticeManagement].[dbo].[ListCache].[ProspectOwnerID] as [Cache].[ProspectOwnerID]))
                                          |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Person_ProspectOwner].[PersonID]), ORDER BY:([Person_ProspectOwner].[PersonID] ASC))
                                          |    |--Clustered Index Scan(OBJECT:([PracticeManagement].[dbo].[Person].[Person_PK] AS [Person_ProspectOwner]), ORDERED FORWARD)
                                          |--Sort(ORDER BY:([Cache].[ProspectOwnerID] ASC))
                                               |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Cache].[ProspectOwnerID]))
                                                    |--Merge Join(Right Outer Join, MERGE:([Person_PrimaryContact].[PersonID])=([Cache].[PrimaryContactID]), RESIDUAL:([PracticeManagement].[dbo].[Person].[PersonID] as [Person_PrimaryContact].[PersonID]=[PracticeManagement].[dbo].[ListCache].[PrimaryContactID] as [Cache].[PrimaryContactID]))
                                                         |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Person_PrimaryContact].[PersonID]), ORDER BY:([Person_PrimaryContact].[PersonID] ASC))
                                                         |    |--Clustered Index Scan(OBJECT:([PracticeManagement].[dbo].[Person].[Person_PK] AS [Person_PrimaryContact]), ORDERED FORWARD)
                                                         |--Sort(ORDER BY:([Cache].[PrimaryContactID] ASC))
                                                              |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Cache].[PrimaryContactID]))
                                                                   |--Merge Join(Right Outer Join, MERGE:([Person_Signatory].[PersonID])=([Cache].[ClientSignatoryID]), RESIDUAL:([PracticeManagement].[dbo].[Person].[PersonID] as [Person_Signatory].[PersonID]=[PracticeManagement].[dbo].[ListCache].[ClientSignatoryID] as [Cache].[ClientSignatoryID]))
                                                                        |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Person_Signatory].[PersonID]), ORDER BY:([Person_Signatory].[PersonID] ASC))
                                                                        |    |--Clustered Index Scan(OBJECT:([PracticeManagement].[dbo].[Person].[Person_PK] AS [Person_Signatory]), ORDERED FORWARD)
                                                                        |--Sort(ORDER BY:([Cache].[ClientSignatoryID] ASC))
                                                                             |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Cache].[ClientSignatoryID]))
                                                                                  |--Merge Join(Right Outer Join, MERGE:([Person_Manager].[PersonID])=([Cache].[ClientManagerID]), RESIDUAL:([PracticeManagement].[dbo].[Person].[PersonID] as [Person_Manager].[PersonID]=[PracticeManagement].[dbo].[ListCache].[ClientManagerID] as [Cache].[ClientManagerID]))
                                                                                       |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Person_Manager].[PersonID]), ORDER BY:([Person_Manager].[PersonID] ASC))
                                                                                       |    |--Clustered Index Scan(OBJECT:([PracticeManagement].[dbo].[Person].[Person_PK] AS [Person_Manager]), ORDERED FORWARD)
                                                                                       |--Sort(ORDER BY:([Cache].[ClientManagerID] ASC))
                                                                                            |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Cache].[ClientManagerID]))
                                                                                                 |--Merge Join(Right Outer Join, MERGE:([Person_Owner].[PersonID])=([Cache].[ClientOwnerID]), RESIDUAL:([PracticeManagement].[dbo].[Person].[PersonID] as [Person_Owner].[PersonID]=[PracticeManagement].[dbo].[ListCache].[ClientOwnerID] as [Cache].[ClientOwnerID]))
                                                                                                      |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Person_Owner].[PersonID]), ORDER BY:([Person_Owner].[PersonID] ASC))
                                                                                                      |    |--Clustered Index Scan(OBJECT:([PracticeManagement].[dbo].[Person].[Person_PK] AS [Person_Owner]), ORDERED FORWARD)
                                                                                                      |--Sort(ORDER BY:([Cache].[ClientOwnerID] ASC))
                                                                                                           |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([Cache].[ClientOwnerID]))
                                                                                                                |--Clustered Index Scan(OBJECT:([PracticeManagement].[dbo].[ListCache].[IX_ListCache_Type] AS [Cache]))

5 个答案:

答案 0 :(得分:2)

假设PersonId是Person表上的主键,并且你在该字段上有一个主键索引(当你指定为PK时会自动发生),那么不,那个PK索引是获取你需要访问的Person表中的七个不同值的最佳方法...而你正在做的是最好的方法......但它不应该扫描人员表七次,它应该遍历Person表上的主键索引七次,速度更快......检查查询计划并确保它正在执行的操作...

答案 1 :(得分:1)

如果较慢的插入,更新和删除对您来说不是问题,您可以为查询创建索引(物化)视图,并从该视图中选择您的记录。

http://technet.microsoft.com/en-us/library/cc917715.aspx

答案 2 :(得分:0)

确保您不仅在Person.PersonID字段上创建了索引,还在Cache中创建了用于连接这两个表的字段。

答案 3 :(得分:0)

您是否尝试使用分析器和DTA来查看它是否显示任何索引?

答案 4 :(得分:0)

一种(相当冗长的)方法是将PersonID和LegalName选择到您感兴趣的每个缓存人员角色的单独临时表中,如下所示:

select [Person].[PersonID], [Person.LegalName]
into #Person_Owner
from [Cache] join [Person] with (nolock)
on [Person].[PersonID] = [Cache].[ClientOwnerID]

然后运行最终查询,将每个Cache Person角色链接到相关的临时表。它是混乱的和冗长的(在代码方面),但它应该确保您只检索每个角色需要的人员记录。

或者,您可以在[Cache]和[Person]之间进行笛卡尔联接,然后使用案例结构来确定哪些Cache角色与哪些Legal Names匹配。它将确保[Person]表仅扫描一次,但结果集将是巨大的;它只比你现有的查询更快,如果它的逻辑读取会降低你的速度,你的数据库服务器上有大量的内存。