如何提高多个内连接的查询性能?

时间:2017-08-27 10:44:27

标签: sql-server performance query-optimization qsqlquery

我有一个查询,需要1分钟才能执行。在查询上花了一些时间之后,我发现有一些部分实际上导致查询花费时间。 有关上述查询,请参阅下面的评论。

完整查询:

SELECT DISTINCT 
    CSU.*, U.txtFirstName, U.txtLastName 
FROM
    tblCRMShallowUsers CSU (NOLOCK) 
INNER JOIN 
    tblUsers U (NOLOCK) ON CSU.PK_autUserID = U.PK_autUserID 
INNER JOIN 
    tblUserGroupLink UGL (NOLOCK) ON U.PK_autUserID = UGL.FK_lngUsersID 
INNER JOIN 
    tblModuleSecurityLinks MSL (NOLOCK) ON FK_lngModuleID = 28 
INNER JOIN 
    tblGroups G (NOLOCK) ON G.PK_autGroupID = MSL.FK_lngGroupID 
WHERE 
    MSL.lngRights > 0
    AND U.lngStatus > 19
    AND U.ysnAdminFlag = 0
    AND G.lngStatus > 19
    AND G.ysnFrontEndGroup = 0
    AND (UGL.FK_lngGroupID = MSL.FK_lngGroupID
         OR UGL.FK_lngGroupID = 2) 
ORDER BY 
    ysnHasAccess DESC, txtLastName, txtFirstName

下面的联接在上面的查询中快速执行:

INNER JOIN 
    tblUsers U (NOLOCK) ON CSU.PK_autUserID = U.PK_autUserID 
INNER JOIN 
    tblUserGroupLink UGL (NOLOCK) ON U.PK_autUserID = UGL.FK_lngUsersID 
INNER JOIN 
    tblModuleSecurityLinks MSL (NOLOCK) ON FK_lngModuleID = 28 
INNER JOIN 
    tblGroups G (NOLOCK) ON G.PK_autGroupID = MSL.FK_lngGroupID 

以上查询中的AND部分实际上正在减慢速度。当我删除这个连接时,它的工作速度非常快,但结果集不是早期的结果。(它返回更多数据)

AND (UGL.FK_lngGroupID = MSL.FK_lngGroupID
     OR UGL.FK_lngGroupID = 2)

如果您能够显示优化查询或某些示例或其他编写相同查询的方法,我将非常感激。

2 个答案:

答案 0 :(得分:0)

由于每个OR谓词的最佳执行计划不同,因此将单个查询重构为单独的SELECT查询和UNION运算符可以提高性能。这允许优化器为每个查询选择独立于另一个的最佳计划。由于DISTINCT从结果中删除了重复的行,因此不需要UNION

SELECT
    CSU.*, U.txtFirstName, U.txtLastName 
FROM
    tblCRMShallowUsers CSU (NOLOCK) 
INNER JOIN 
    tblUsers U (NOLOCK) ON CSU.PK_autUserID = U.PK_autUserID 
INNER JOIN 
    tblUserGroupLink UGL (NOLOCK) ON U.PK_autUserID = UGL.FK_lngUsersID 
INNER JOIN 
    tblModuleSecurityLinks MSL (NOLOCK) ON FK_lngModuleID = 28 
INNER JOIN 
    tblGroups G (NOLOCK) ON G.PK_autGroupID = MSL.FK_lngGroupID 
WHERE 
    MSL.lngRights > 0
    AND U.lngStatus > 19
    AND U.ysnAdminFlag = 0
    AND G.lngStatus > 19
    AND G.ysnFrontEndGroup = 0
    AND UGL.FK_lngGroupID = MSL.FK_lngGroupID
UNION
SELECT
    CSU.*, U.txtFirstName, U.txtLastName 
FROM
    tblCRMShallowUsers CSU (NOLOCK) 
INNER JOIN 
    tblUsers U (NOLOCK) ON CSU.PK_autUserID = U.PK_autUserID 
INNER JOIN 
    tblUserGroupLink UGL (NOLOCK) ON U.PK_autUserID = UGL.FK_lngUsersID 
INNER JOIN 
    tblModuleSecurityLinks MSL (NOLOCK) ON FK_lngModuleID = 28 
INNER JOIN 
    tblGroups G (NOLOCK) ON G.PK_autGroupID = MSL.FK_lngGroupID 
WHERE 
    MSL.lngRights > 0
    AND U.lngStatus > 19
    AND U.ysnAdminFlag = 0
    AND G.lngStatus > 19
    AND G.ysnFrontEndGroup = 0
    AND UGL.FK_lngGroupID = 2 
ORDER BY 
    ysnHasAccess DESC, txtLastName, txtFirstName;

另一方面,请注意,NOLOCKREAD_UNCOMMITTED隔离级别可能会导致在分配顺序扫描期间跳过或重复行,如果在查询运行时更新数据。只有在并发性比正确结果更重要时才应使用脏读。

答案 1 :(得分:0)

@DanGuzman @flaschenpost我也尝试用CTE方法将连接分成2个seaprate东西,但它没有工作,并且花了相同的时间(1分钟)。 您能否看一下我试过的以下查询。

  1. 使用CTE方法:With UsersUserGroupLink AS( Select U.PK_autUserID, U.txtFirstName, U.txtLastName, U.lngStatus, U.ysnAdminFlag, UGL.FK_lngGroupID FROM tblUsers as U (NOLOCK) INNER JOIN tblUserGroupLink as UGL (NOLOCK) ON U.PK_autUserID = UGL.FK_lngUsersID ), GroupsModuleSecurityLinks AS(Select MSL.lngRights, G.lngStatus, G.ysnFrontEndGroup, MSL.FK_lngGroupID From
    tblModuleSecurityLinks as MSL (NOLOCK) INNER JOIN tblGroups as G (NOLOCK) ON G.PK_autGroupID = MSL.FK_lngGroupID AND MSL.FK_lngModuleID = 28 ) (SELECT DISTINCT CSU.*, UsersUserGroupLink.txtFirstName, UsersUserGroupLink.txtLastName FROM UsersUserGroupLink Inner join
    tblCRMShallowUsers as CSU ON UsersUserGroupLink.PK_autUserID =
    CSU.PK_autUserID Inner join GroupsModuleSecurityLinks ON
    GroupsModuleSecurityLinks.FK_lngGroupID =
    UsersUserGroupLink.FK_lngGroupID or UsersUserGroupLink.FK_lngGroupID = 2 WHERE GroupsModuleSecurityLinks.lngRights > 0 AND UsersUserGroupLink.lngStatus > 19 AND UsersUserGroupLink.ysnAdminFlag = 0 AND GroupsModuleSecurityLinks.lngStatus > 19 AND GroupsModuleSecurityLinks.ysnFrontEndGroup = 0) ORDER BY ysnHasAccess DESC, txtLastName, txtFirstName