2016-12-01 2 views
0

Ich versuche, eine dynamische SQL-Abfrage, die mehr als 200M Datensätze laden soll. Ich habe versucht, alle Datensätze auf einmal zu laden, aber 'System.OutOfMemory' Ausnahme daher entschieden, das Zeitintervall in Monaten zu brechen.Das Folgende läuft für mehr als eine Stunde, obwohl, wenn ich es nur für einen Monat ausführen. Ich habe die Daten fest programmiert und ohne das 'While' ausgeführt und es läuft normal. Kann jemand überprüfen und lassen Sie mich wissen, wenn es einen Fehler darin gibt. Im Folgenden finden Sie meine AnfrageDynamic SQL läuft viel zu lange

DECLARE @FromDate VARCHAR(MAX)='', 
     @params nvarchar(max) = N'@StartDate Date out,@EndDate Date out,@FromDate date out,@ToDate date out', 
     @SQL NVARCHAR(MAX)=’’, 
     @ToDate VARCHAR(MAX)='', 
     @StartDate VARCHAR(MAX)=’’, 
     @EndDate VARCHAR(MAX)=’’; 

SELECT @FromDate= DATEADD(DAY,-365, GETUTCDATE()), @ToDate =  GETUTCDATE(); 
SELECT @[email protected], @EndDate=CAST(DATEADD(MONTH,1, @FromDate) AS DATE); 
SET @SQL = ' 
WHILE ''' + @FromDate + ''' < ''' + @ToDate + ''' 
    BEGIN 
    INSERT INTO dbo.Sales 
    (
    ProductID, 
    SaleDate, 
    Quantity 
    ) 
Select 
     ProductID, 
     SaleDate, 
     Quantity 
from 
    OPENQUERY(TeraData1,'' 
     Select 
     PR_ID   AS ProductID, 
     SL_Date   AS SaleDate, 
     PR_QTY   AS Quantity 
    FROM 
     Sales.Product 
    where 
SaleDate BETWEEN ' + @StartDate + 'AND '+ @EndDate + ' 
'') 

SET @FromDate =DATEADD(MONTH,1,'''+ @FromDate +''') 
SET @StartDate =DATEADD(MONTH,1,'''+ @StartDate +''') 
SET @EndDate =DATEADD(MONTH,1,'''+ @EndDate +''') 
END’ 

EXECUTE sp_executesql @SQL, @params, 
       @[email protected], 
       @[email protected], 
       @StartDate = @StartDate out, 
       @EndDate = @EndDate out; 
+1

Warum nicht gespeicherte Prozedur/Funktionslogik anstelle von dynamischen SQL? –

+1

@TonyDong hat einen Punkt, es gibt nichts in der Syntax, die Sie verwenden, die dynamische sql erfordern würde, könnten Sie reguläre WHILE-Steuersyntax verwenden. Und was ist das Problem, obwohl es ein wenig schwierig zu sagen ist, dass Sie den Umfang der Variablen zwischen in der dynamischen SQL und in Ihrem Kontrollfluss mischen – Matt

+1

Und Sie mischen Datentypen auch einige, die Teil des Problems sein könnte – Matt

Antwort

2
DECLARE @FromDate DATE 

SET @FromDate = DATEADD(YEAR,-1,GETUTCDATE()) 

WHILE @FromDate < GETUTCDATE() 
BEGIN 
    INSERT INTO dbo.Sales 
    (
     ProductID, 
     SaleDate, 
     Quantity 
    ) 
Select 
     ProductID, 
     SaleDate, 
     Quantity 
from 
    OPENQUERY(TeraData1, 
     Select 
      PR_ID   AS ProductID, 
      SL_Date   AS SaleDate, 
      PR_QTY   AS Quantity 
     FROM 
      Sales.Product 
     where 
      SaleDate >= @FromDate AND SaleDate < DATEADD(MONTH,1,@FromDate) 
    ) 

    SET @FromDate =DATEADD(MONTH,1,@FromDate) 
END 

Es sieht aus wie Sie viel mehr Variablen/Termine haben, als Sie brauchen, und dass Sie dynamische SQL nicht brauchen, wenn Sie die verknüpfte Servernamen oder eine andere fehlen passieren Spalte dynamisch.

Halten Sie auch mit dem entsprechenden Datentyp für den Parameter, anstatt SQL die gewünschten Werte ableiten zu lassen.

Auch Ihre Verwendung von BETWEEN für die Daten hätte die bestimmten Daten dupliziert, weil es einschließlich sein würde, Grenze 1 Seite des Vergleichs zu beheben.

Wenn Sie diese dynamisch den Steuerungsablauf in Ihrer nicht dynamischen SQL halten tun wollen und die Parameter übergeben hier ein Beispiel:

DECLARE @FromDate DATE 

SET @FromDate = DATEADD(YEAR,-1,GETUTCDATE()) 

WHILE @FromDate < GETUTCDATE() 
BEGIN 

    DECLARE @LinkedServerName NVARCHAR(MAX) = 'TeraData1' 
    DECLARE @ParamDef NVARCHAR(MAX) = '@FromDate DATE' 
    DECLARE @SQL NVARCHAR(MAX) 

    SET @SQL = ' 
     INSERT INTO dbo.Sales 
     (
     ProductID, 
     SaleDate, 
     Quantity 
    ) 
    Select 
     ProductID, 
     SaleDate, 
     Quantity 
    from 
     OPENQUERY(' + @LinkedServerName + ', 
      Select 
      PR_ID   AS ProductID, 
      SL_Date   AS SaleDate, 
      PR_QTY   AS Quantity 
      FROM 
      Sales.Product 
      where 
      SaleDate >= @FromDate AND SaleDate < DATEADD(MONTH,1,@FromDate) 
     )' 

    EXECUTE sp_executesql @SQL, @PramDef, @FromDate = @FromDate 

    SET @FromDate =DATEADD(MONTH,1,@FromDate) 
END