如何提高多个内连接的查询性能?
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] 时更新数据,请注意 NOLOCK
和 READ_UNCOMMITTED
隔离级别可能会导致在分配顺序扫描期间跳过或复制行=].仅当并发性比正确结果更重要时才应使用脏读。
@DanGuzman @flaschenpost 我也在尝试使用 CTE 方法将连接分成 2 个独立的东西,但它没有工作并且花费了与原来相同的时间(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
我有一个查询需要 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] 时更新数据,请注意 NOLOCK
和 READ_UNCOMMITTED
隔离级别可能会导致在分配顺序扫描期间跳过或复制行=].仅当并发性比正确结果更重要时才应使用脏读。
@DanGuzman @flaschenpost 我也在尝试使用 CTE 方法将连接分成 2 个独立的东西,但它没有工作并且花费了与原来相同的时间(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