Die Abfrage wird sehr langsam ausgeführt. Gibt es eine Möglichkeit, sie weiter zu verbessern?


9

Ich habe die folgende Abfrage und aufgrund vieler SUMFunktionsaufrufe wird meine Abfrage zu langsam ausgeführt. Ich habe viele Datensätze in meiner Datenbank und möchte für jeden einen Bericht aus dem aktuellen und dem letzten Jahr (letzte 30 Tage, letzte 90 Tage und letzte 365 Tage) erhalten:

SELECT 
    b.id as [ID]
    ,d.[Title] as [Title]
    ,e.Class as [Class]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 30 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 30 Days Col2]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 90 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 90 Days Col2]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 365 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 365 Days Col2]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 30 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 30 Days Col2]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 90 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 90 Days Col2]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 365 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 365 Days Col2]


    FROM 
    tb1 a
INNER JOIN 
    tb2 b on a.id=b.fid and a.col3 = b.col4
INNER JOIN 
    tb3 c on b.fid = c.col5
INNER JOIN       
    tb4 d on c.id = d.col6
INNER JOIN 
    tb5 e on c.col7 = e.id
GROUP BY
    b.id, d.Title, e.Class

Hat jemand eine Idee, wie ich meine Abfrage verbessern kann, um schneller zu laufen?

BEARBEITEN: Ich wurde ermutigt, den DATEADDFunktionsaufruf in die whereAnweisung zu verschieben und zuerst zwei Jahre zu laden und dann in Spalten zu filtern. Ich bin jedoch nicht sicher, ob die vorgeschlagene Antwort ausgeführt wird und funktioniert. Sie finden sie hier: https: // stackoverflow. com / a / 59944426/12536284

Wenn Sie mit der oben genannten Lösung einverstanden sind, zeigen Sie mir bitte, wie ich sie in meiner aktuellen Abfrage anwenden kann.

Nur zu Ihrer Information, ich verwende diesen SP in C #, Entity Framework (DB-First), ungefähr so:

var result = MyDBEntities.CalculatorSP();

4
Zeigen Sie uns Ihren Ausführungsplan ...
Dale K

1
Auf irgendetwas - kann die Abfrage verlangsamen
Fabio


2
Bitte senden Sie erneut den Ausführungsplan.
SQL Police

2
Wir sehen das immer noch nicht Execution Plan. Bitte
poste

Antworten:


10

Wie bereits erwähnt, ist der Ausführungsplan in diesem Fall sehr hilfreich. Basierend auf dem, was Sie gezeigt haben, haben Sie anscheinend 12 Spalten mit insgesamt 15 Spalten extrahiert tb1 (a), sodass Sie versuchen können, Ihre Abfrage ohne Verknüpfung und nur gegen die auszuführen tb1, um festzustellen, ob Ihre Abfrage wie erwartet funktioniert. Da ich nichts Falsches an Ihren SUM-Funktionsaufrufen sehen kann, ist meine beste Vermutung, dass Sie ein Problem mit Ihren Joins haben. Ich würde Folgendes vorschlagen. Sie können beginnen, indem Sie beispielsweise den letzten Join INNER JOIN tb5 e on c.col7 = e.idund die damit verbundene Verwendung wie e.Class as [Class]und ausschließene.Classin Ihrer Gruppe nach Aussage. Wir werden es nicht vollständig ausschließen. Dies ist nur ein Test, um sicherzustellen, ob das Problem damit besteht oder nicht. Wenn Ihre Abfrage besser ausgeführt wird und Sie wie erwartet versuchen können, eine temporäre Tabelle als Problemumgehung anstelle des letzten Joins zu verwenden , etwas wie das:

SELECT *
INTO #Temp
FROM
  (
     select * from tb5
  ) As tempTable;

SELECT 
    b.id as [ID]
    ,d.[Title] as [Title]
    ,e.Class as [Class]

    -- SUM Functions

FROM 
    tb1 a
INNER JOIN 
    tb2 b on a.id=b.fid and a.col3 = b.col4
INNER JOIN 
    tb3 c on b.fid = c.col5
INNER JOIN       
    tb4 d on c.id = d.col6
INNER JOIN 
    #Temp e on c.col7 = e.id
GROUP BY
    b.id, d.Title, e.Class

Temporäre Tabellen sind Tabellen, die vorübergehend auf dem SQL Server vorhanden sind. Die temporären Tabellen sind nützlich, um die unmittelbaren Ergebnismengen zu speichern, auf die mehrmals zugegriffen wird. Weitere Informationen finden Sie hier https://www.sqlservertutorial.net/sql-server-basics/sql-server-temporary-tables/ Und hier https://codingsight.com/introduction-to-temporary-tables-in -SQL Server/

Außerdem würde ich dringend empfehlen, wenn Sie die gespeicherte Prozedur verwenden, setzen Sie diese Option NOCOUNTauf ON, sie kann auch eine erhebliche Leistungssteigerung bewirken, da der Netzwerkverkehr stark reduziert wird:

SET NOCOUNT ON
SELECT *
INTO #Temp
-- The rest of code

Basierend darauf :

SET NOCOUNT ON ist eine set-Anweisung, die die Nachricht verhindert, die die Anzahl der von T-SQL-Abfrageanweisungen betroffenen Zeilen anzeigt. Dies wird in gespeicherten Prozeduren und Triggern verwendet, um zu vermeiden, dass die betroffene Zeilennachricht angezeigt wird. Die Verwendung von SET NOCOUNT ON innerhalb einer gespeicherten Prozedur kann die Leistung der gespeicherten Prozedur erheblich verbessern.


1
Können Sie mir bitte erklären , warum das Kopieren von ganzen tb5auf den #TempTisch und Verbinden der temporären Tabelle schneller arbeiten als zum Verbinden tb5direkt? Sicherlich enthalten sie dieselben Daten (und #Tempmöglicherweise fehlt ein Index, wenn er in vorhanden war tb5). Ich kann wirklich nicht verstehen, warum dies effizienter ist (soweit ich weiß, sollte es weniger effizient sein, alle Daten zu kopieren und beizutreten).
Zick

2
@zig Sie haben in diesem Fall Recht, aber was ist, wenn sich das tb5auf einem anderen Server befindet? In diesem Fall ist die Verwendung einer temporären Tabelle definitiv schneller als die direkte Verknüpfung mit einem anderen Server. Das war nur ein Vorschlag, um zu testen und zu sehen, ob sich etwas geändert hat. Ich hatte in der Vergangenheit eine ähnliche Situation, und es scheint, dass die temporäre Tabelle dem OP zum Glück auch in diesem Fall geholfen hat.
Salah Akbari

2

Der beste Ansatz ist das Einfügen in eine Tabellenvariable / Hash-Tabelle (wenn die Zeilenanzahl klein ist, verwenden Sie eine Tabellenvariable oder eine Hash-Tabelle, wenn die Zeilenanzahl ziemlich groß ist). Aktualisieren Sie dann die Aggregation und wählen Sie schließlich aus der Tabellenvariablen oder Hash-Tabelle aus. Ein Blick in den Abfrageplan ist erforderlich.

DECLARE @MYTABLE TABLE (ID INT, [Title] VARCHAR(500), [Class] VARCHAR(500),
[Current - Last 30 Days Col1] INT, [Current - Last 30 Days Col2] INT,
[Current - Last 90 Days Col1] INT,[Current - Last 90 Days Col2] INT,
[Current - Last 365 Days Col1] INT, [Current - Last 365 Days Col2] INT,
[Last year - Last 30 Days Col1] INT, [Last year - Last 30 Days Col2] INT,
[Last year - Last 90 Days Col1] INT, [Last year - Last 90 Days Col2] INT,
[Last year - Last 365 Days Col1] INT, [Last year - Last 365 Days Col2] INT)



INSERT INTO @MYTABLE(ID, [Title],[Class], 
[Current - Last 30 Days Col1], [Current - Last 30 Days Col2],
[Current - Last 90 Days Col1], [Current - Last 90 Days Col2],
[Current - Last 365 Days Col1], [Current - Last 365 Days Col2],
[Last year - Last 30 Days Col1], [Last year - Last 30 Days Col2],
[Last year - Last 90 Days Col1], [Last year - Last 90 Days Col2],
[Last year - Last 365 Days Col1], [Last year - Last 365 Days Col2]
  )
SELECT    b.id  ,d.[Title] ,e.Class ,0,0,0,0,0,0,0,0,0,0,0,0        
FROM     tb1 a
INNER JOIN   tb2 b on a.id=b.fid and a.col3 = b.col4
INNER JOIN   tb3 c on b.fid = c.col5
INNER JOIN   tb4 d on c.id = d.col6
INNER JOIN  tb5 e on c.col7 = e.id
GROUP BY b.id, d.Title, e.Class

UPDATE T 
SET [Current - Last 30 Days Col1]=K.[Current - Last 30 Days Col1] , 
[Current - Last 30 Days Col2]    =K.[Current - Last 30 Days Col2],
[Current - Last 90 Days Col1]    = K.[Current - Last 90 Days Col1], 
[Current - Last 90 Days Col2]    =K.[Current - Last 90 Days Col2] ,
[Current - Last 365 Days Col1]   =K.[Current - Last 365 Days Col1], 
[Current - Last 365 Days Col2]   =K.[Current - Last 365 Days Col2],
[Last year - Last 30 Days Col1]  =K.[Last year - Last 30 Days Col1],
 [Last year - Last 30 Days Col2] =K.[Last year - Last 30 Days Col2],
[Last year - Last 90 Days Col1]  =K.[Last year - Last 90 Days Col1], 
[Last year - Last 90 Days Col2]  =K.[Last year - Last 90 Days Col2],
[Last year - Last 365 Days Col1] =K.[Last year - Last 365 Days Col1],
 [Last year - Last 365 Days Col2]=K.[Last year - Last 365 Days Col2]
    FROM @MYTABLE T JOIN 
     (
SELECT 
    b.id as [ID]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Current - Last 30 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Current - Last 30 Days Col2]

    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Current - Last 90 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Current - Last 90 Days Col2]

    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Current - Last 365 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Current - Last 365 Days Col2]

    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Last year - Last 30 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Last year - Last 30 Days Col2]

    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Last year - Last 90 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Last year - Last 90 Days Col2]

    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Last year - Last 365 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Last year - Last 365 Days Col2]
    FROM     tb1 a
INNER JOIN   tb2 b on a.id=b.fid and a.col3 = b.col4
INNER JOIN   tb3 c on b.fid = c.col5
INNER JOIN   tb4 d on c.id = d.col6
INNER JOIN  tb5 e on c.col7 = e.id
GROUP BY    b.id
) AS K ON T.ID=K.ID


SELECT *
FROM @MYTABLE

0

Ich gehe davon aus, dass tb1 eine große Tabelle ist (relativ zu tb2, tb3, tb4 und tb5).

In diesem Fall ist es hier sinnvoll, die Auswahl dieser Tabelle einzuschränken (mit einer WHERE-Klausel).

Wenn nur ein kleiner Teil von tb1 verwendet wird, z. B. weil die Verknüpfungen mit tb2, tb3, tb4 und tb5 die erforderlichen Zeilen auf nur wenige Prozent reduzieren, sollten Sie überprüfen, ob die Tabellen in den Spalten indiziert sind, die Sie in den Verknüpfungen verwenden .

Wenn ein großer Teil von tb1 verwendet wird, kann es sinnvoll sein, die Ergebnisse zu gruppieren, bevor sie mit tb2, tb3, tb4 und tb5 verknüpft werden. Unten ist ein Beispiel dafür.

SELECT 
    b.id as [ID]
    ,d.[Title] as [Title]
    ,e.Class as [Class]
    ,SUM(a.[Current - Last 30 Days Col1]) AS [Current - Last 30 Days Col1]
    ,SUM(a.[Current - Last 30 Days Col2]) AS [Current - Last 30 Days Col2]
    ,SUM(a.[Current - Last 90 Days Col1]) AS [Current - Last 90 Days Col1]
    -- etc.
    FROM (
      SELECT a.id, a.col3

      ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 30 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 30 Days Col2]

      ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 90 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 90 Days Col2]

      ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 365 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 365 Days Col2]

      ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 30 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 30 Days Col2]

      ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 90 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 90 Days Col2]

      ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 365 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 365 Days Col2]

      FROM  tb1 a
      WHERE a.DateCol >= DATEADD(YEAR,-2,GETDATE())
      GROUP BY a.id, a.col3
    ) AS a
INNER JOIN 
    tb2 b on a.id=b.fid and a.col3 = b.col4
INNER JOIN 
    tb3 c on b.fid = c.col5
INNER JOIN       
    tb4 d on c.id = d.col6
INNER JOIN 
    tb5 e on c.col7 = e.id
GROUP BY
    b.id, d.Title, e.Class

Es wäre weitaus besser, zuerst den Ausführungsplan anzuzeigen und dann Entscheidungen über die Erstellung von Indizes und die Neuerstellung von Statistiken zu treffen.
SQL Police

Ich hasse es wirklich, dass mein Beitrag eine negative Bewertung erhält, ohne zu erklären, warum. Natürlich stimme ich zu, dass man den Ausführungsplan überprüfen muss, um das Leistungsproblem auf den Punkt zu bringen. Trotzdem stehe ich zu meiner Empfehlung, die Indizes auf Fremdschlüssel zu überprüfen, die für die Abfrage relevant sind.
Gert-Jan

1
Sie "nehmen" etwas an, ohne es zu wissen. Sie posten also eine Antwort auf der Grundlage des Unbekannten. Deshalb abstimmen. Es ist besser, das OP anzuweisen, seine Frage zu verbessern, indem Sie den Ausführungsplan veröffentlichen.
SQL Police

Das ist nicht alles, was ich geschrieben habe. Persönlich würde ich nur abstimmen, wenn die Antwort schlecht oder falsch ist, nicht wenn ich einfach nicht einverstanden bin. Aber danke für die Antwort.
Gert-

In gewisser Weise ist es falsch, denn wie können Sie beweisen, dass es richtig ist?
SQL Police


0

Um solche Berechnungen zu optimieren, sollten Sie einige der Werte vorberechnen. Die Idee von Vorberechnungen besteht darin, die Anzahl der Zeilen zu reduzieren, die gelesen oder fortgesetzt werden müssen.

Eine Möglichkeit, dies zu erreichen, ist die Verwendung einer indizierten Ansicht und die Engine die Berechnungen selbst durchführen zu lassen. Da diese Art von Ansichten einige Einschränkungen aufweist, erstellen Sie am Ende eine einfache Tabelle und führen stattdessen die Berechnungen durch. Grundsätzlich hängt es von den geschäftlichen Anforderungen ab.

Im folgenden Beispiel erstelle ich eine Tabelle mit RowIDund RowDatetimeSpalten und füge 1 Million Zeilen ein. Ich verwende eine indizierte Ansicht, um die Entitäten pro Tag zu zählen. Anstatt 1 Million Zeilen pro Jahr abzufragen, frage ich 365 Zeilen pro Jahr ab, um diese Metriken zu zählen.

DROP TABLE IF EXISTS [dbo].[DataSource];
GO

CREATE TABLE [dbo].[DataSource]
(
    [RowID] BIGINT IDENTITY(1,1) PRIMARY KEY
   ,[RowDateTime] DATETIME2
);

GO

DROP VIEW IF EXISTS [dbo].[vw_DataSource];
GO

CREATE VIEW [dbo].[vw_DataSource] WITH SCHEMABINDING
AS
SELECT YEAR([RowDateTime]) AS [Year]
      ,MONTH([RowDateTime]) AS [Month]
      ,DAY([RowDateTime]) AS [Day]
      ,COUNT_BIG(*) AS [Count]
FROM [dbo].[DataSource]
GROUP BY YEAR([RowDateTime])
        ,MONTH([RowDateTime])
        ,DAY([RowDateTime]);
GO

CREATE UNIQUE CLUSTERED INDEX [IX_vw_DataSource] ON [dbo].[vw_DataSource]
(
    [Year] ASC,
    [Month] ASC,
    [Day] ASC
);

GO

DECLARE @min bigint, @max bigint
SELECT @Min=1 ,@Max=1000000

INSERT INTO [dbo].[DataSource] ([RowDateTime])
SELECT TOP (@Max-@Min+1) DATEFROMPARTS(2019,  1.0 + floor(12 * RAND(convert(varbinary, newid()))), 1.0 + floor(28 * RAND(convert(varbinary, newid())))          )       
FROM master..spt_values t1 
CROSS JOIN master..spt_values t2

GO


SELECT *
FROM [dbo].[vw_DataSource]


SELECT SUM(CASE WHEN DATEFROMPARTS([Year], [Month], [Day]) >= DATEADD(MONTH,-1,GETDATE()) THEN [Count] ELSE 0 END) as [Current - Last 30 Days Col1]
      ,SUM(CASE WHEN DATEFROMPARTS([Year], [Month], [Day]) >= DATEADD(QUARTER,-1,GETDATE()) THEN [Count] ELSE 0 END) as [Current - Last 90 Days Col1]
      ,SUM(CASE WHEN DATEFROMPARTS([Year], [Month], [Day]) >= DATEADD(YEAR,-1,GETDATE()) THEN [Count] ELSE 0 END) as [Current - Last 365 Days Col1]
FROM [dbo].[vw_DataSource];

Der Erfolg einer solchen Lösung hängt stark davon ab, wie die Daten verteilt sind und wie viele Zeilen Sie haben. Wenn Sie beispielsweise für jeden Tag des Jahres einen Eintrag pro Tag haben, stimmen Ansicht und Tabelle mit den Zeilen überein, sodass die E / A-Vorgänge nicht reduziert werden.

Das Obige ist nur ein Beispiel für das Materialisieren und Lesen der Daten. In Ihrem Fall müssen Sie möglicherweise weitere Spalten zur Ansichtsdefinition hinzufügen.


0

Ich würde eine Nachschlagetabelle "Dates" verwenden, um meine Daten mit einem Index für DatesId zu verknüpfen. Ich verwende die Daten als Filter, wenn ich historische Daten durchsuchen möchte. Der Join ist schnell und daher die Filterung, da die DatesId ein Clustered-Primärindex (Primärschlüssel) ist. Fügen Sie auch die Datumsspalte (als eingeschlossene Spalte) für Ihre Datentabelle hinzu.

Die Datumstabelle enthält die folgenden Spalten:

DatesId, Date, Year, Quarter, YearQuarter, MonthNum, MonthNameShort, YearWeek, WeekNum, DayOfYear, DayOfMonth, DayNumOfWeek, DayName

Beispieldaten: 20310409 2031-04-09 2031 2 2031-Q2 4. April Apr 2031_15 15 99 9 3 Mittwoch

Sie können mir eine PM senden, wenn Sie eine CSV davon möchten, damit Sie sie in die Datenbank importieren können, aber ich bin sicher, dass Sie so etwas online leicht finden und Ihre eigene erstellen können.

Ich füge auch eine Identitätsspalte hinzu, damit Sie für jedes Datum eine Ganzzahl erhalten können. Dies erleichtert die Arbeit etwas, ist jedoch keine Voraussetzung.

SELECT * FROM dbo.dates where dateIndex BETWEEN (getDateIndexDate(getDate())-30 AND getDateIndexDate(getDate())+0) --30 days ago

Dadurch kann ich leicht zu einer bestimmten Zeit zurückspringen. Es ist ganz einfach, eigene Ansichten dazu zu erstellen. Sie können die Funktion ROW_NUMBER () natürlich auch für Jahre, Wochen usw. verwenden.

Sobald ich den gewünschten Datenbereich habe, verbinde ich mich mit den Daten. Funktioniert sehr schnell!


0

Da Sie Werte immer basierend auf einer ganzen Anzahl von Monaten gruppieren, würde ich zuerst in einer Unterabfrage in der from-Klausel nach Monat gruppieren. Dies ähnelt der Verwendung einer temporären Tabelle. Nicht sicher, ob dies Ihre Anfrage tatsächlich beschleunigen würde.

SELECT f.id, f.[Title], f.Class,
    SUM(CASE WHEN f.MonthDiff = 1 THEN col1 ELSE 0 END) as [Current - Last 30 Days Col1],
    -- etc
FROM (
    SELECT 
        b.id,
        d.[Title],
        e.Class,
        DateDiff(Month, a.DateCol, GETDATE()) as MonthDiff,
        Sum(a.col1) as col1,
        Sum(a.col2) as col2
    FROM  tb1 a
    INNER JOIN tb2 b on a.id = b.fid and a.col3 = b.col4
    INNER JOIN tb3 c on b.fid = c.col5
    INNER JOIN tb4 d on c.id = d.col6
    INNER JOIN tb5 e on c.col7 = e.id
    WHERE a.DateCol between DATEADD(YEAR,-2,GETDATE() and GETDATE()
    GROUP BY b.id, d.Title, e.Class, DateDiff(Month,  a.DateCol, GETDATE())
) f
group by f.id, f.[Title], f.Class

-2

Um die Geschwindigkeit der SQL-Abfrage zu verbessern, müssen Sie Indizes hinzufügen. Für jede verknüpfte Tabelle müssen Sie einen Index hinzufügen.

Wie dieses Codebeispiel für Orakel:

CREATE INDEX supplier_idx
ON supplier (supplier_name);

Das ist kein schlechter Vorschlag. Sie sehen aus dem OP, dass eine temporäre Tabelle ohne Index erstellt wird - INNER JOIN #Temp e auf c.col7 = e.id. Obwohl die Antwort noch verbesserungswürdig ist, denke ich nicht, dass sie massenhaft herabgestuft werden sollte. speziell für einen neuen Benutzer.
smoore4

@ smoore4 Stimmen Sie zu, diese Option des Downvotings ohne klares Argument sollte entfernt werden. Es gibt einen großen Missbrauch dieser Funktionalität
Greggz
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.