2017-08-27 4 views
0

Ich habe eine Abfrage, die 1 Minute dauert, um auszuführen. Nachdem ich einige Zeit mit der Abfrage verbracht habe, habe ich festgestellt, dass es einen Teil gibt, der die Abfrage tatsächlich dazu veranlasst, sich die Zeit zu nehmen. Bitte beachten Sie meine Kommentare unten für die Abfrage erwähnt.Wie kann die Abfrageleistung für mehrere innere Verknüpfungen verbessert werden?

komplette Abfrage:

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 

Below Joins ausführen schnell in der obigen Abfrage:

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 

Hier ist das UND-Teil in der obigen Abfrage, die es wirklich verlangsamt. Wenn ich diese entfernen beitreten es sehr schnell gearbeitet, aber die Ergebnismenge ist nicht das Ergebnis, das früher kommen würde. (Es mehr Daten zurückgibt)

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

Ich würde wirklich schätzen, wenn Sie irgendeine Richtung zeigen kann, um die Abfrage zu optimieren oder ein Beispiel oder eine andere Möglichkeit, dieselbe Abfrage zu schreiben.

+0

Haben Sie versucht, das Hinzufügen richtigen Indizes Tabellen? –

+1

Set [Schlechte Angewohnheiten, NOLOCK überall hinzuschieben] (http://blogs.sqlsentry.com/aaronbertrand/bad-habits-nolock-everywhere/) - es ist * nicht empfehlenswert *, dies überall zu benutzen - im Gegenteil! –

+0

https://meta.stackoverflow.com/questions/333952/why-should-i-provide-an-mcve-for-what-seems-to-me-to-be-very-simple-sql-query ZB fügen Sie einige Zeilen von 'create ...' und 'insert ...' in Ihren Code ein, um eine Grundlage für Tests und Demonstrationen zu geben. – Yunnosch

Antwort

0

Da sich der optimale Ausführungsplan mit jedem der Prädikate OR unterscheidet, wird die Leistung verbessert, indem die einzelne Abfrage als separate SELECT-Abfragen und ein UNION-Operator refactoriert wird. Dies ermöglicht dem Optimierer, den besten Plan für jede Abfrage unabhängig von dem anderen auszuwählen. DISTINCT wird nicht benötigt, da UNION doppelte Zeilen aus dem Ergebnis entfernt.

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; 

Auf einer Seite zur Kenntnis, beachten Sie als NOLOCK und die READ_UNCOMMITTED Isolationsstufe führen kann Zeilen bei der Zuordnung, um Scans dupliziert übersprungen oder werden, wenn Daten aktualisiert werden, während die Abfrage ausgeführt wird. Dirty Reads sollten nur verwendet werden, wenn Nebenläufigkeit wichtiger ist als korrekte Ergebnisse.

0

@DanGuzman @flaschenpost Ich habe auch versucht mit CTE-Ansatz, um die Joins in 2 seaprate Dinge zu teilen, aber es funktionierte nicht und nahm die gleiche Zeit wie es war (1 Minute). Könnten Sie bitte einen Blick auf die unten stehende Abfrage werfen, die ich ausprobiert habe.

  1. Mit CTE Ansatz: 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
Verwandte Themen