我有一个SQL查询,它在MSSQL 2008 R2上运行
视图vMobileLastMobileHistory
有大约1000行和
select * from vMobileLastMobileHistory
花费0.2秒
但是此查询需要5秒钟,我该如何优化此代码? (我认为问题是INTERSECT,但我不知道如何改变这个)
SELECT DISTINCT *
FROM
(
SELECT vMobileLastMobileHistory.*
FROM vMobileLastMobileHistory
LEFT OUTER JOIN MobileType_DomainAction ON
MobileType_DomainAction.tiMobileType = vMobileLastMobileHistory.tiMobileType
LEFT OUTER JOIN MobileType_User ON
MobileType_User.MobileID = MobileType_DomainAction.ID
WHERE MobileType_User.UserID = @UserID OR @UserID = - 1
INTERSECT
SELECT vMobileLastMobileHistory.*
FROM vMobileLastMobileHistory
LEFT OUTER JOIN dbo.Region_User ON
dbo.vMobileLastMobileHistory.strRegion = dbo.Region_User.strRegion
WHERE Region_User.iSystemUser = @UserID OR @UserID = - 1
INTERSECT
SELECT vMobileLastMobileHistory.*
FROM vMobileLastMobileHistory
LEFT OUTER JOIN Contractor_User ON
vMobileLastMobileHistory.strContractor = Contractor_User.strContractor
WHERE Contractor_User.iSystemUser = @UserID OR @UserID = - 1
)
答案 0 :(得分:1)
问题是,如果您的iSytemUser
列上有任何索引,则优化无法使用它们,因为它必须考虑要传递的特定用户ID,或者返回所有结果,最好是逻辑上分开你的两个案件。此外,由于您不关心辅助表中的任何列,因此您可以在特定用户的情况下使用EXISTS
来利用半连接:
IF (@UserID = -1)
BEGIN
SELECT DISTINCT *
FROM vMobileLastMobileHistory;
END
ELSE
BEGIN
SELECT DISTINCT *
FROM vMobileLastMobileHistory AS mh
WHERE EXISTS
( SELECT 1
FROM Contractor_User AS cu
WHERE cu.strContractor = mh.strContractor
AND cu.iSystemUser = @UserID
)
AND EXISTS
( SELECT 1
FROM Region_User AS ru
WHERE ru.strRegion = mh.strRegion
AND ru.iSystemUser = @UserID
)
AND EXISTS
( SELECT 1
FROM MobileType_DomainAction AS da
INNER JOIN MobileType_User AS mu
ON mu.MobileID = da.ID
WHERE da.tiMobileType = mh.tiMobileType
AND mu.iSystemUser = @UserID
);
END
现在,每个案例可以有两个执行计划(返回所有结果,或者针对特定用户),在每种情况下,您只需要从vMobileLastMobileHistory
读取一次,并且还限制删除所需的排序INTERSECT
并替换为3 EXISTS
条款。
如果它们不存在,那么您也可以考虑在表上使用某些索引。查找索引有用的一个好方法是在SQL Server Management Studio中使用选项" Show Actual Execution Plan"运行查询。启用后,这将显示任何缺失的索引。
答案 1 :(得分:0)
Most of time Intersect
and Inner Join
will be same。你没有共享你的数据,所以根据我的知识和这个链接,我只是将交叉查询替换为内连接查询:
- 我认为你不需要明确的上层查询。如果您有问题通知我。
SELECT DISTINCT vml.*
FROM vMobileLastMobileHistory vml
LEFT OUTER JOIN MobileType_DomainAction mtda ON mtda.tiMobileType = vml.tiMobileType
LEFT OUTER JOIN MobileType_User ON MobileType_User.MobileID = mtda.ID
LEFT OUTER JOIN dbo.Region_User ON dbo.vml.strRegion = dbo.Region_User.strRegion
LEFT OUTER JOIN Contractor_User ON vml.strContractor = Contractor_User.strContractor
WHERE
(MobileType_User.UserID = @UserID
and Region_User.iSystemUser = @UserID or Contractor_User.iSystemUser = @UserID
) OR @UserID = - 1