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

How to improve query performance for multiple inner joins?

我有一个查询需要 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 部分确实减慢了速度。当我删除此连接时,它运行得非常快,但结果集不是之前出现的结果。(它 returns 更多数据)

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

如果您能展示一些优化查询的方向或一些示例或其他编写相同查询的方式,我将不胜感激。

由于每个 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;

附带说明,如果在查询 [=22] 时更新数据,请注意 NOLOCKREAD_UNCOMMITTED 隔离级别可能会导致在分配顺序扫描期间跳过或复制行=].仅当并发性比正确结果更重要时才应使用脏读。

@DanGuzman @flaschenpost 我也在尝试使用 CTE 方法将连接分成 2 个独立的东西,但它没有工作并且花费了与原来相同的时间(1 分钟)。 你能看看下面我试过的查询吗?

  1. 使用 CTE 方法:使用 UsersUserGroupLink AS( Select U.PK_autUserID, U.txtFirstName, U.txtLastName, U.lngStatus, U.ysnAdminFlag, UGL.FK_lngGroupID 来自 tblUsers 作为 U (NOLOCK) INNER JOIN tblUserGroupLink 作为 UGL (NOLOCK) ON U.PK_autUserID = UGL.FK_lngUsersID ), GroupsModuleSecurityLinks AS(Select MSL.lngRights, G.lngStatus, G.ysnFrontEndGroup, MSL.FK_lngGroupID 来自<br> tblModuleSecurityLinks 作为 MSL (NOLOCK) INNER JOIN tblGroups 作为 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<br> tblCRMShallowUsers 作为 CSU ON UsersUserGroupLink.PK_autUserID =<br> CSU.PK_autUserID 内加入 GroupsModuleSecurityLinks ON<br> GroupsModuleSecurityLinks.FK_lngGroupID =<br> UsersUserGroupLink.FK_lngGroupID 或 UsersUserGroupLink.FK_lngGroupID = 2 哪里 GroupsModuleSecurityLinks.lngRights > 0 和 UsersUserGroupLink.lngStatus > 19 和 UsersUserGroupLink.ysnAdminFlag = 0 和 GroupsModuleSecurityLinks.lngStatus > 19 和 GroupsModuleSecurityLinks.ysnFrontEndGroup = 0) 订购方式 ysnHasAccess DESC、txtLastName、txtFirstName