2017-06-06 4 views
0

Ich habe eine Abfrage in einer gespeicherten Prozedur, die Daten aus mehreren Tabellen meiner SQL Server-Datenbank abruft. Von meiner Anwendung aus rufe ich diese gespeicherte Prozedur mit einigen Parametern auf, um die Daten zu filtern.Abfrage in SQL Server gespeicherte Prozedur dauert länger für bestimmte Daten als für alle Daten

Die seltsame Sache ist, dass für alle Daten für "X" Woche des Jahres (etwa 2600 Datensätze) dauert es etwa 30 Sekunden, um die Daten abzurufen. Aber wenn ich einen spezifischen "Center" -Filter für die gleiche Woche des Jahres hinzufüge (ungefähr 1800 Datensätze), dauert es ungefähr 3 Minuten, um die Daten zu erhalten!

Wenn ich nur die Abfrage ausführen, funktioniert es gut (30 Sekunden für alle Daten und etwa 22 Sekunden für gefilterte Daten). Das Problem ist, wenn ich die Abfrage durch die gespeicherte Prozedur ausführen!

Wie ist das möglich? Warum benötigen gefilterte Daten etwa x6-mal mehr als alle Daten? Warum vermisse ich? Schreib ich die gespeicherte Prozedur korrekt? Wie kann ich das effizienter machen?

Mein Code der gespeicherten Prozedur ist so etwas wie folgt aus:

ALTER PROCEDURE EventMonitoring 
    @EventType AS CHAR(1), 
    @Year AS INT, 
    @Week AS INT, 
    @CenterID AS CHAR(2), 
    @AreaID AS INT 
AS 
    DECLARE @SQLCommand AS VARCHAR(MAX) 
    DECLARE @MessageError AS VARCHAR(MAX) 

    SET @SQLCommand = ' SELECT .... 
        .... 
        .... 
        .... 
        FROM Event E 
        INNER JOIN ... 
        INNER JOIN ... 
        INNER JOIN ... 
        WHERE E.EventYear = ' + CAST(@Year AS VARCHAR) + 
        ' And E.EventWeek = ' + CAST(@Week AS VARCHAR) + 
        ' And E.EventType = ' + CAST(@EventType AS VARCHAR) 

    IF @Centro <> '-' --If application sends - as the parameter, it gets all centers 
    BEGIN 
     @SQLCommand = @SQLCommand + ' AND E.CenterID = ''' + @CenterID + '''' 
    END 

    IF @Area <> 0 --If application sends 0 as the parameter, it gets all areas 
    BEGIN 
     @SQLCommand = @SQLCommand + ' AND E.AreaID = ' + CAST(@AreaID AS VARCHAR) 
    END 

    SET @SQLCommand = @SQLCommand + 'GROUP BY ....' 

    BEGIN TRY 
     EXEC(@SQLCommand) 
    END TRY 
    BEGIN CATCH 
     .... 
    END CATCH 
+1

Können Sie die Tabellenstruktur anzeigen und Indizes darauf? Wie viele Zeilen in der Tabelle? – SchmitzIT

+0

Was passiert, wenn Sie Ihre Abfrage außerhalb des Prozesses mit 'DBCC FREEPROCCACHE' ausführen? Spiegelt die Ausführungszeit die Ausführungszeiten Ihres SP besser wider? – scsimon

+1

Zeigen Sie uns beide Pläne? https://www.brentozar.com/pastetheplan/ –

Antwort

1

Egal, wie Das wackelt, ich wette, das kann gelöst werden, indem eine zusätzliche Spalte (CenterId) zu einem Index hinzugefügt wird.

Wenn der Unterschied zu "wenn ich eine zusätzliche Spalte zur WHERE-Klausel hinzufügen, die Abfrage dauert sehr viel länger", das bedeutet, dass die zusätzliche Spalte ist nicht abgedeckt durch den Index die Abfrage ohne verwendet werden kann diese Klausel.

Um das zu beheben, finden Sie den vorhandenen Index die Abfrage ohne die zusätzliche Klausel verwendet und die zusätzliche Spalte in die include() dieses Index hinzufügen oder einen neuen Index machen (scheint verschwenderisch einen ganz neuen Index machen eine weitere hinzuzufügen int Spalte aber).

Suchen Sie den Index, der für Event mit der schnellen Abfrage verwendet wird, und ob es CenterId enthält. Wenn Sie nicht wissen, wie Sie es finden können, müssen Sie im Grunde die Ausführungspläne überprüfen. Wenn Sie es immer noch nicht finden können, können Sie Ihre Ausführungspläne teilen und wir werden Ihnen helfen, es zu finden. Teilen Sie Ihre Ausführungspläne mit Paste The Plan @ brentozar.com hier sind die Anweisungen: How to Use Paste the Plan.

ich nur vermuten kann (vage), was der Index wie ohne mehr zu wissen, aussehen wird, wie Event auf den Rest Ihrer Abfrage verknüpft, aber der Index etwas wie dies nur aussehen könnte, fehlt CenterId:

create nonclustered index ix_Event_cover 
    on dbo.Event(EventYear,EventWeek,EventType) 
    include (CenterId, AreaID, [JoinColumns], [SelectedColumns]) 
+0

Ok, ich werde es versuchen, aber warum, wenn ich die Abfrage selbst ausführe funktioniert es gut? Das Problem kam nur auf, wenn ich genau die gleiche Abfrage über den SP mit einer String-Abfrage ausführen –

+0

@GustavoAlvarado Das wäre etwas, was Sie die Ausführungspläne überprüfen/einfügen würden, um herauszufinden. Es gibt einige obskure Möglichkeiten, aber es lohnt sich nicht, sich mit ihnen zu befassen, bis Sie sich bemühen, Ausführungspläne für Ihre Frage aufzunehmen. – SqlZim

+0

Dank @SqlZim, beim Generieren des Abfrageplans erkannte ich, dass es einen fehlenden Index gab, der das Problem löste –

0

stand ich vor einer Situation wie dieser bei meiner Arbeit und wir lösen das Hinzufügen nur den SET ARITHABORT ON Parameter innerhalb der proc, weil die ADO-Verbindungen.

EDIT

Wenn eine Prozedur das Skript in Runtime-SQL-Engine erzeugt nicht die tatsächlichen Parameter sehen einen guten Plan für die Abfrage zu erstellen. Es ist Anruf Parameter Sniffing. So versuchen, so etwas wie dieses:

ALTER PROCEDURE EventMonitoring 
    @EventType AS CHAR(1), 
    @Year AS INT, 
    @Week AS INT, 
    @CenterID AS CHAR(2), 
    @AreaID AS INT 
AS 
    DECLARE @MessageError AS VARCHAR(MAX) 

    BEGIN TRY 

    IF @Centro <> '-' --If application sends - as the parameter, it gets all centers 
    BEGIN 
     SELECT .... 
        .... 
        .... 
        .... 
        FROM Event E 
        INNER JOIN ... 
        INNER JOIN ... 
        INNER JOIN ... 
        WHERE E.EventYear = @Year 
        And E.EventWeek = @Week 
        And E.EventType =EventType AND E.CenterID = @CenterID 
        GROUP BY .... 
    END 

    IF @Area <> 0 --If application sends 0 as the parameter, it gets all areas 
    BEGIN 

     SELECT .... 
        .... 
        .... 
        .... 
        FROM Event E 
        INNER JOIN ... 
        INNER JOIN ... 
        INNER JOIN ... 
        WHERE E.EventYear = @Year 
        And E.EventWeek = @Week 
        And E.EventType =EventType AND E.AreaID = @AreaID 
        GROUP BY .... 
    END 





    END TRY 
    BEGIN CATCH 
     .... 
    END CATCH 

Ein weiterer Versuch

Nach einem schnell lesen im Artikel darauf durch SqlZim versuchen, diese letzte Schuss mit ARITHABORT ON und option(recompile)

ALTER PROCEDURE EventMonitoring 
     @EventType AS CHAR(1), 
     @Year AS INT, 
     @Week AS INT, 
     @CenterID AS CHAR(2), 
     @AreaID AS INT 
    AS 
SET ARITHABORT ON 
     DECLARE @SQLCommand AS VARCHAR(MAX) 
     DECLARE @MessageError AS VARCHAR(MAX) 

     SET @SQLCommand = ' SELECT .... 
         .... 
         .... 
         .... 
         FROM Event E 
         INNER JOIN ... 
         INNER JOIN ... 
         INNER JOIN ... 
         WHERE E.EventYear = ' + CAST(@Year AS VARCHAR) + 
         ' And E.EventWeek = ' + CAST(@Week AS VARCHAR) + 
         ' And E.EventType = ' + CAST(@EventType AS VARCHAR) 

     IF @Centro <> '-' --If application sends - as the parameter, it gets all centers 
     BEGIN 
      @SQLCommand = @SQLCommand + ' AND E.CenterID = ''' + @CenterID + '''' 
     END 

     IF @Area <> 0 --If application sends 0 as the parameter, it gets all areas 
     BEGIN 
      @SQLCommand = @SQLCommand + ' AND E.AreaID = ' + CAST(@AreaID AS VARCHAR) 
     END 

     SET @SQLCommand = @SQLCommand + 'GROUP BY .... OPTION (RECOMPILE)' 

     BEGIN TRY 
      EXEC(@SQLCommand) 
     END TRY 
     BEGIN CATCH 
      .... 
     END CATCH 
+0

Ich benutze auch ADO, aber, in meinem Fall, wenn ich den SP direkt ausführe, geschieht dasselbe, nicht nur wenn ich das anrufe SP von ADO –

+0

In diesem Fall empfehle ich stark, die String-Abfrage in echte Abfrage zu konvertieren. – Krismorte

+0

Das ist nicht ganz richtig. Die existierende Prozedur erzeugt einen neuen Ausführungsplan für jede Ausführung, Ihre Version wird dem Parameter Sniffing und verwandten Problemen unterworfen. [Parameter Sniffing, Einbettung und die RECOMPILE Optionen - Paul White] (https://sqlperformance.com/2013/08/t-sql-queries/parameter-sniffing-embedding-and-the-recompile-options) – SqlZim

Verwandte Themen