我有这样的查询(向右剥离)是这样的:
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]))
答案 0 :(得分:2)
假设PersonId
是Person表上的主键,并且你在该字段上有一个主键索引(当你指定为PK时会自动发生),那么不,那个PK索引是获取你需要访问的Person表中的七个不同值的最佳方法...而你正在做的是最好的方法......但它不应该扫描人员表七次,它应该遍历Person表上的主键索引七次,速度更快......检查查询计划并确保它正在执行的操作...
答案 1 :(得分:1)
如果较慢的插入,更新和删除对您来说不是问题,您可以为查询创建索引(物化)视图,并从该视图中选择您的记录。
答案 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]表仅扫描一次,但结果集将是巨大的;它只比你现有的查询更快,如果它的逻辑读取会降低你的速度,和你的数据库服务器上有大量的内存。