如何提高此查询的性能?

时间:2015-10-09 09:47:07

标签: sql-server sql-server-2008

我有一个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
    )

2 个答案:

答案 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