La query viene eseguita molto lentamente, esiste un modo per migliorarla ulteriormente?


9

Ho la seguente query e, a causa di molte SUMchiamate di funzione, la mia query funziona troppo lentamente. Ho molti record nel mio database e vorrei ricevere un rapporto dell'anno corrente e dell'anno scorso (ultimi 30 giorni, ultimi 90 giorni e ultimi 365 giorni) per ognuno:

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

Qualcuno ha idea di come posso migliorare la mia query per funzionare più velocemente?

EDIT: Sono stato incoraggiato a spostare la DATEADDchiamata di funzione wherenell'istruzione e caricarli prima due anni, quindi filtrarli in colonne, ma non sono sicuro che la risposta suggerita sia eseguita e funzioni, è possibile trovarla qui: https: // stackoverflow. COM / a / 59944426/12536284

Se sei d'accordo con la soluzione sopra, mostrami come posso applicarla nella mia domanda attuale?

Cordiali saluti, sto usando questo SP in C #, Entity Framework (DB-First), qualcosa del genere:

var result = MyDBEntities.CalculatorSP();

4
Mostraci il tuo piano di esecuzione ...
Dale K

1
ON nulla - è ciò che può rallentare la query
Fabio


2
Ancora una volta, si prega di pubblicare il piano di esecuzione.
SQL Police

2
Ancora non stiamo vedendo il Execution Plan. Per favore pubblicalo
Arun Palanisamy il

Risposte:


10

Come già accennato, il piano di esecuzione sarà davvero utile in questo caso. Sulla base di ciò che hai mostrato sembra che tu abbia estratto da 12 colonne di 15 colonne totali tb1 (a), quindi puoi provare a eseguire la tua query senza alcun join e solo contro tb1per vedere se la tua query funziona come previsto. Dato che non riesco a vedere nulla di male nelle chiamate della funzione SUM, la mia ipotesi migliore è che tu abbia un problema con i tuoi join, suggerirei di fare quanto segue. Puoi iniziare escludendo l'ultimo join, ad esempio, INNER JOIN tb5 e on c.col7 = e.ide qualsiasi utilizzo correlato di esso come e.Class as [Class]ee.Classnel tuo gruppo per dichiarazione. Non lo escluderemo completamente, questo è solo un test per assicurarsi che il problema sia o meno, se la tua query funziona meglio e come previsto puoi provare a usare una tabella temporanea come soluzione alternativa invece dell'ultimo join , qualcosa come questo:

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

In realtà, le tabelle temporanee sono tabelle che esistono temporaneamente su SQL Server. Le tabelle temporanee sono utili per memorizzare i set di risultati immediati a cui si accede più volte. Puoi leggere ulteriori informazioni qui https://www.sqlservertutorial.net/sql-server-basics/sql-server-temporary-tables/ E qui https://codingsight.com/introduction-to-temporary-tables-in -server SQL/

Inoltre consiglio vivamente, se si utilizza la Stored Procedure, di impostare NOCOUNTsu ON, può anche fornire un significativo aumento delle prestazioni, poiché il traffico di rete è notevolmente ridotto:

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

Sulla base di questo :

SET NOCOUNT ON è un'istruzione set che impedisce il messaggio che mostra il numero di righe interessate dalle istruzioni della query T-SQL. Viene utilizzato all'interno di stored procedure e trigger per evitare di mostrare il messaggio relativo alle righe interessate. L'uso di SET NOCOUNT ON all'interno di una procedura memorizzata può migliorare le prestazioni della procedura memorizzata con un margine significativo.


1
Puoi spiegare perché la copia completa tb5della #Temptabella e l'unione della tabella temporanea funzionano più rapidamente rispetto alla connessione tb5diretta? sicuramente contengono gli stessi dati (e #Temppotrebbe mancare un indice se esistesse tb5). Non riesco davvero a capire perché questo sia più efficiente (per quanto ne so dovrebbe essere meno efficiente copiare tutti i dati e unirli).
zig

2
@zig Hai ragione in questo caso, ma cosa succede se tb5si trova in un altro server? In questo caso l'utilizzo di una tabella temporanea è decisamente più rapido rispetto all'adesione diretta a un altro server. Questo è stato solo un suggerimento per testare e vedere se qualcosa è cambiato Ho avuto una situazione simile in passato, e per fortuna sembra che la tabella temporanea abbia aiutato l'OP anche in questo caso.
Salah Akbari,

2

L'approccio migliore è quello di inserire in una tabella variabile / tabella hash (se il conteggio delle righe è piccolo, utilizzare una variabile di tabella o utilizzare una tabella hash se il conteggio delle righe è piuttosto grande). Quindi aggiorna l'aggregazione e infine seleziona dalla variabile tabella o dalla tabella hash. È necessario esaminare il piano di query.

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

Suppongo che tb1 sia una tabella di grandi dimensioni (relativa a tb2, tb3, tb4 e tb5).

In tal caso, ha senso qui limitare la selezione di quella tabella (con una clausola WHERE).

Se viene utilizzata solo una piccola parte di tb1, ad esempio perché i join con tb2, tb3, tb4 e tb5 riducono le righe necessarie solo di qualche percento, è necessario verificare se le tabelle sono indicizzate sulle colonne utilizzate nei join .

Se viene utilizzata una grande parte di tb1, può essere sensato raggruppare i risultati prima di unirli a tb2, tb3, tb4 e tb5. Di seguito è riportato un esempio.

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

Sarebbe molto meglio prima visualizzare il piano di esecuzione, quindi prendere decisioni sulla creazione di indici e la ricostruzione di statistiche.
SQL Police

Odio davvero che il mio post ottenga un punteggio negativo senza alcuna spiegazione del perché. Naturalmente sono d'accordo sul fatto che per arrivare al nocciolo del problema delle prestazioni, è necessario ispezionare il piano di esecuzione. Detto questo, sono fedele alla mia raccomandazione di controllare gli indici per eventuali chiavi esterne che sono rilevanti nella query.
Gert-

1
"Assumi" qualcosa senza saperlo. Quindi pubblichi una risposta sulla base dell'ignoto. Pertanto downvote. È meglio incaricare il PO di migliorare la sua domanda pubblicando il piano di esecuzione.
SQL Police

Non è tutto ciò che ho scritto. Personalmente, farei un voto negativo solo se la risposta è cattiva o sbagliata, non quando non sono semplicemente d'accordo. Ma grazie per aver risposto.
Gert-

In un certo senso è sbagliato, perché come si può dimostrare che è corretto?
SQL Police


0

Per ottimizzare tali calcoli, ti consigliamo di pre-calcolare alcuni dei valori. L'idea dei pre-calcoli è di ridurre il numero di righe che devono essere lette o proseguite.

Un modo per raggiungere questo obiettivo è utilizzare una vista indicizzata e lasciare che il motore esegua i calcoli da solo. Poiché questo tipo di viste presenta alcune limitazioni, si finisce per creare una tabella semplice ed eseguire invece i calcoli. Fondamentalmente, dipende dalle esigenze aziendali.

Quindi, nell'esempio seguente sto creando una tabella con RowIDe RowDatetimecolonne e inserendo 1 milione di righe. Sto usando una vista indicizzata per contare le entità al giorno, quindi invece di eseguire una query su 1 milione di righe all'anno, eseguirò una query su 365 righe all'anno per contare queste metriche.

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];

Il successo di tale soluzione dipende in larga misura dalla distribuzione dei dati e dal numero di righe disponibili. Ad esempio, se si dispone di una voce al giorno per ogni giorno dell'anno, la vista e la tabella avranno la stessa corrispondenza di righe, quindi le operazioni di I / O non verranno ridotte.

Inoltre, quanto sopra è solo un esempio di materializzazione dei dati e lettura. Nel tuo caso potrebbe essere necessario aggiungere più colonne alla definizione della vista.


0

Vorrei utilizzare una tabella di ricerca "Date" per unire i miei dati con un indice su DatesId. Uso le date come filtro quando voglio sfogliare i dati storici. Il join è veloce e quindi il filtro come DatesId è indice primario cluster (chiave primaria). Aggiungi anche la colonna della data (come colonna inclusa) per la tabella dei dati.

La tabella delle date ha le seguenti colonne:

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

Dati di esempio: 20310409 2031-04-09 2031 2 2031-Q2 4 aprile 2031_15 15 99 9 3 mercoledì

Puoi PM me se vuoi un csv di questo in modo da poterlo importare nel database, ma sono sicuro che puoi facilmente trovare qualcosa di simile online e crearne uno tuo.

Aggiungo anche una colonna di identità in modo da poter ottenere un numero intero per ogni data. Questo rende un po 'più facile lavorare con, ma non un requisito.

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

Questo mi permette di tornare facilmente indietro a un certo periodo. È abbastanza facile creare le tue opinioni su questo. Ovviamente puoi usare la funzione ROW_NUMBER () per farlo anche per anni, settimane, ecc.

Una volta che ho il daterange che desidero, mi unisco ai dati. Funziona molto velocemente!


0

Dal momento che stai sempre raggruppando i valori in base a un numero intero di mesi, vorrei prima raggruppare per mese in una sottoquery nella clausola from. Questo è simile all'utilizzo di una tabella temporanea. Non sono sicuro se ciò acceleri effettivamente la query.

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

Per migliorare la velocità della query SQL, è necessario aggiungere indici. Per ogni tabella unita, devi aggiungere un indice.

Come questo esempio di codice per Oracle:

CREATE INDEX supplier_idx
ON supplier (supplier_name);

questo non è un cattivo suggerimento. dall'OP si vede che viene creata una tabella temporanea senza indice - INNER JOIN #Temp e on c.col7 = e.id. mentre esiste un margine di miglioramento nella risposta, non credo che dovrebbe essere sottoposto a downgrade in massa. in particolare per un nuovo utente.
smoore4,

@ smoore4 D'accordo, questa opzione di downvoting senza un chiaro argomento dovrebbe essere rimossa. C'è un grande uso improprio di questa funzionalità
Greggz il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.