Hohe E / A für einen Teil der Abfrage

7

Ich habe eine große Abfrage, die ich einstellen möchte. Ich schreibe viele Abfragen, habe aber nicht viel abgestimmt. Ich habe einen Screenshot von SQL Sentry Plan Explorer Free (SSPEF) beigefügt:

Hohe E / A.

Im obigen Teil des Plans enthält die Tabelle pb_WorkRquestLog 229.001 Zeilen. Der Abfrageplan zeigt jedoch ca. 348 Millionen Zeilen (229.001 x 1.520 Iterationen):

Geben Sie hier die Bildbeschreibung ein

Da es keine where-Klausel gibt, verwendet die Abfrage einen Clustered Index Scan. Ich habe alle Indizes mit FULLSCAN neu erstellt und alle Statistiken aktualisiert.

Der Code, den dieser Teil des Plans ausführt, lautet:

select distinct 
            wrs.ServiceKey 
            , owner.DepartmentName AS GroupName
            , owner.UserName AS UserId
            , owner.WRLCreateDateTime
            , owner.WRLNotes
            , wrx.CreatedDate as WRCreateDateTime
            , wrx.Id
            , wrx.Description 
            , cast(wrx.Notes as varchar(2500)) as Notes
        from    
            prism72ext.dbo.pb_WorkRequestService wrs 
            Join prism72ext.dbo.pb_WorkRequest wrx on (wrs.WorkRequestId = wrx.Id and wrx.Status = 'Incomplete')
            left join (
                select
                    wl.WorkRequestId
                    ,   d.Name AS DepartmentName
                    ,   u.UserName
                    , wl.CreatedDate as WRLCreateDateTime
                    , cast(wl.Notes as varchar(2500)) as WRLNotes
                from
                    (
                        SELECT     
                            MAX( Id ) AS Id
                        FROM          
                                prism72ext.dbo.pb_WorkRequestLog WITH(INDEX(0))
                        GROUP BY 
                            WorkRequestId
                    ) mwl
                    join prism72ext.dbo.pb_WorkRequestLog wl on mwl.Id = wl.Id
                    join prism72Ext.dbo.pb_Department d ON wl.DepartmentId = d.DepartmentId
                    left join prism72Ext.dbo.pb_User u on wl.UserId = u.UserId
                ) owner on wrs.WorkRequestId = owner.WorkRequestId

SSPEF meldet, dass die tatsächliche Datengröße bei 5 Millionen logischen Lesevorgängen fast 5 GB beträgt! SSMS meldet, dass die Tabelle nur 16 MB groß ist.

Ich habe die Abfrage von 4m28s auf 1m35s reduziert, aber jetzt stecke ich fest. Ich wäre dankbar, wenn mich jemand in die richtige Richtung weisen könnte, um damit umzugehen.

Bearbeiten: Jemand schlug vor, "OPTION (HASH JOIN, MERGE JOIN)" zu versuchen. Dies machte einen dramatischen Unterschied. Die E / A wurde massiv reduziert und die Abfrage wurde in 13 Sekunden ausgeführt.

Hat jemand Probleme mit dieser Lösung?

Alan T.
quelle
Kommentare sind nicht für eine ausführliche Diskussion gedacht. Dieses Gespräch wurde in den Chat verschoben .
Paul White 9

Antworten:

1

Wenn Sie noch keinen haben, erstellen Sie einen zusammengesetzten Index prism72ext.dbo.pb_WorkRequestLog(WorkRequestId, Id DESC)ohne Cluster und führen Sie die Abfrage ohne den Indexhinweis aus .

Lassen Sie stattdessen Ihre innere Auswahl für die ownerabgeleitete Tabelle zurückgeben .mwl.WorkRequestIdml.WorkRequestId

Bruce Dunwiddie
quelle
Hallo Shriop, ich habe diesen Index, aber ohne DESC. Ich habe die von Ihnen vorgeschlagenen Änderungen vorgenommen, aber es hat keinen großen Unterschied gemacht. Ich habe die Frage mit einer Lösung aktualisiert. Könnten Sie sich die Lösung ansehen und angeben, ob Sie sie für angemessen halten?
Alan T
Dies hängt davon ab, wie wichtig diese Abfrage für Ihr System ist. Es ist wahrscheinlich ziemlich angemessen als Lösung für ein Problem, das Sie mit begrenztem Kontext über das Internet lösen möchten. Im Allgemeinen sind Hinweise immer zu vermeiden und neigen dazu, auf ein zugrunde liegendes Problem hinzuweisen, aber es ist wahrscheinlich etwas, das ich etwa eine Stunde lang auf Ihrem Server sitzen müsste, um Abfragen auszuführen und besser zu lösen. Bei jedem blauen Mond gibt es etwas, das fast einen Hinweis erfordert, aber ich habe immer noch das Gefühl, dass es wahrscheinlich sogar meine eigenen Lücken zeigt, wenn dies passiert, und nicht, dass es technisch benötigt wird.
Bruce Dunwiddie
Wenn es wirklich der Kern Ihres Systems ist, würde ich vorschlagen, mit diesem "Fix" in die Produktion zu wechseln, aber weiterhin zu recherchieren und zu verstehen, warum, je nachdem, wie viel Zeit Sie investieren müssen.
Bruce Dunwiddie
Es scheint, dass Sie nach dem "neuesten" (dh dem höchsten ID) Rekord pb_WorkRequestLogfür einen bestimmten suchen WorkRequestId. Kann bei Vorhandensein dieses Index über einer Fensterfunktion ( ROW_NUMBER() OVER (PARTITION BY pb_WorkRequestLog ORDER BY ID DESC) eine bessere Leistung erzielt werden.
Mustaccio
0

Die Verwendung des Hinweises INDEX (0) erzwingt den Clustered-Index-Scan. Wenn Sie dies vermeiden möchten, müssen Sie den Hinweis entfernen. TABELLENHINWEISE :

Wenn ein Clustered-Index vorhanden ist, erzwingt INDEX (0) einen Clustered-Index-Scan und INDEX (1) einen Clustered-Index-Scan oder eine Suche. Wenn kein Clustered-Index vorhanden ist, erzwingt INDEX (0) einen Tabellenscan und INDEX (1) wird als Fehler interpretiert.

Sie können auch versuchen, einen nicht gruppierten Index für WorkRequestId zu erstellen und die Spalten CreatedDate und Notes mithilfe der INCLUDE-Klausel einzuschließen. Beachten Sie jedoch, dass dies negative Auswirkungen auf die Einfügeleistung und die Größe der Tabelle haben kann.

Wenn Sie den Datenbanknamen in Abfragen fest codieren, ist es äußerst schwierig, den Code in Testumgebungen zu verschieben, es sei denn, Sie können sich eine einzelne Datenbank pro Serverinstanz leisten.

Piotr Rodak
quelle