2017-08-27 74 views
0

我有一个需要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 (UGL.FK_lngGroupID = MSL.FK_lngGroupID 
    OR UGL.FK_lngGroupID = 2) 

我真的很感激,如果你能表现出一定的方向,以优化查询或者编写相同查询的一些示例或其他方式。

+0

您是否尝试过加入适量的索引到你的表? –

+1

集[坏习惯踢 - 把NOLOCK到处(http://blogs.sqlsentry.com/aaronbertrand/bad-habits-nolock-everywhere/) - 是*不推荐*到处使用这个 - 恰恰相反! –

+0

https://meta.stackoverflow.com/questions/333952/why-should-i-provide-an-mcve-for-what-seems-to-me-to-be-a-very-simple-sql-query即在代码中添加一些'create ...'和'insert ...'行,为测试和演示奠定基础。 – Yunnosch

回答

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隔离级别可能导致跳过或在分配顺序扫描复制行如果查询运行时数据被更新。脏读只能在并发比正确结果更重要时使用。

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