La requête s'exécute très lentement, existe-t-il un moyen de l'améliorer davantage?

9

J'ai la requête suivante, et en raison de nombreux SUMappels de fonction, ma requête s'exécute trop lentement. J'ai beaucoup d'enregistrements dans ma base de données et je voudrais obtenir un rapport de l'année en cours et de l'année dernière (30 derniers jours, 90 derniers jours et 365 derniers jours) pour chacun:

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

Quelqu'un a-t-il une idée de comment puis-je améliorer ma requête afin d'exécuter plus rapidement?

EDIT: J'ai été encouragé à déplacer l' DATEADDappel de fonction vers l' whereinstruction et à charger d'abord les deux premières années, puis à les filtrer en colonnes, mais je ne suis pas sûr que la réponse suggérée soit exécutée et fonctionne, elle pourrait être trouvée ici: https: // stackoverflow. com / a / 59944426/12536284

Si vous êtes d'accord avec la solution ci-dessus, veuillez me montrer comment puis-je l'appliquer dans ma requête actuelle?

Juste pour info, j'utilise ce SP en C #, Entity Framework (DB-First), quelque chose comme ceci:

var result = MyDBEntities.CalculatorSP();
Jim
la source
4
Montrez-nous votre plan d'exécution ...
Dale K
1
SUR n'importe quoi - c'est ce qui peut ralentir la requête
Fabio
2
Encore une fois, veuillez publier le plan d'exécution.
SQL Police
2
Nous ne voyons toujours pas le Execution Plan. Veuillez l'afficher
Arun Palanisamy

Réponses:

10

Comme cela a déjà été mentionné, le plan d'exécution sera vraiment utile dans ce cas. Sur la base de ce que vous avez montré, il semble que vous ayez extrait 12 colonnes de 15 colonnes au total tb1 (a), vous pouvez donc essayer d'exécuter votre requête sans aucune jointure et juste tb1pour voir si votre requête fonctionne comme prévu. Étant donné que je ne vois rien de mal avec vos appels de fonction SUM, ma meilleure supposition est que vous avez un problème avec vos jointures, je suggère de faire ce qui suit. Vous pouvez commencer par exclure la dernière jointure par exemple, INNER JOIN tb5 e on c.col7 = e.idet toute utilisation connexe comme e.Class as [Class]ete.Classdans votre groupe par déclaration. Nous n'allons pas l'exclure complètement, c'est juste un test pour vous assurer que le problème est ou non, si votre requête fonctionne mieux et comme prévu, vous pouvez essayer d'utiliser une table temporaire comme solution de contournement au lieu de la dernière jointure , quelque chose comme ça:

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

En fait, les tables temporaires sont des tables qui existent temporairement sur le serveur SQL. Les tables temporaires sont utiles pour stocker les jeux de résultats immédiats auxquels on accède plusieurs fois. Vous pouvez en savoir plus à ce sujet ici https://www.sqlservertutorial.net/sql-server-basics/sql-server-temporary-tables/ Et ici https://codingsight.com/introduction-to-temporary-tables-in -serveur SQL/

Je recommande également fortement, si vous utilisez la procédure stockée, définissez la valeur NOCOUNTsur ON, cela peut également améliorer considérablement les performances, car le trafic réseau est considérablement réduit:

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

Sur cette base :

SET NOCOUNT ON est une instruction set qui empêche le message indiquant le nombre de lignes affectées par les instructions de requête T-SQL. Ceci est utilisé dans les procédures stockées et les déclencheurs pour éviter d'afficher le message des lignes affectées. L'utilisation de SET NOCOUNT ON dans une procédure stockée peut améliorer considérablement les performances de la procédure stockée.

Salah Akbari
la source
1
Pouvez-vous expliquer pourquoi la copie entière tb5sur la #Temptable et la jonction de la table temporaire fonctionnent plus rapidement que la jonction tb5directe? ils contiennent sûrement les mêmes données (et il #Temppeut manquer un index s'il existait en tb5). Je ne comprends vraiment pas pourquoi cela est plus efficace (pour autant que je sache, il devrait être moins efficace de copier toutes les données et de les rejoindre).
zig
2
@zig Vous avez raison dans ce cas, mais que faire si le tb5se trouve sur un autre serveur? Dans ce cas, l'utilisation d'une table temporaire est nettement plus rapide que la jointure directe à un autre serveur. Ce n'était qu'une suggestion pour tester et voir si quelque chose a changé. J'ai eu une situation similaire dans le passé, et il semble heureusement que la table temporaire a également aidé le PO dans ce cas.
Salah Akbari
2

La meilleure approche consiste à insérer dans une variable de table / table de hachage (si le nombre de lignes est petit, utilisez une variable de table ou utilisez une table de hachage si le nombre de lignes est assez gros). Mettez ensuite à jour l'agrégation, puis sélectionnez enfin la variable de table ou la table de hachage. Il est nécessaire d'examiner le plan de requête.

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
Harshana
la source
0

Je suppose que tb1 est un grand tableau (par rapport à tb2, tb3, tb4 et tb5).

Si c'est le cas, il est logique ici de restreindre la sélection de cette table (avec une clause WHERE).

Si seule une petite partie de tb1 est utilisée, par exemple parce que les jointures avec tb2, tb3, tb4 et tb5 réduisent les lignes nécessaires à quelques pour cent seulement, vous devez vérifier si les tables sont indexées sur les colonnes que vous utilisez dans les jointures .

Si une grande partie de tb1 est utilisée, il peut être judicieux de regrouper ses résultats avant de les joindre à tb2, tb3, tb4 et tb5. En voici un exemple.

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
Gert-Jan
la source
Il serait bien préférable de voir d'abord le plan d'exécution, puis de prendre des décisions sur la création d'index et la recréation de statistiques.
SQL Police
Je déteste vraiment que mon message obtienne un score négatif sans aucune explication. Bien sûr, je conviens que pour aller au cœur du problème de performance, il faut inspecter le plan d'exécution. Cela dit, je maintiens ma recommandation de vérifier les index pour toutes les clés étrangères pertinentes dans la requête.
Gert-
1
Vous "supposez" quelque chose sans le savoir. Vous publiez donc une réponse sur la base de l'inconnu. Par conséquent, downvote. Il vaut mieux demander au PO d'améliorer sa question en affichant le plan d'exécution.
SQL Police
Ce n'est pas tout ce que j'ai écrit. Personnellement, je ne voterais que si la réponse est mauvaise ou fausse, pas quand je suis tout simplement en désaccord. Mais merci d'avoir répondu.
Gert-
D'une certaine manière, c'est faux, car comment prouver que c'est correct?
SQL Police
0

Utilisez simplement des colonnes calculées

Exemple

ALTER TABLE tb1 ADD [Current - Last 30 Days Col1] AS (CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col1 ELSE 0 END) PERSISTED;

Spécifiez les colonnes calculées dans une table

Dawid Wekwejt
la source
0

Pour optimiser ces calculs, vous pouvez envisager de pré-calculer certaines des valeurs. L'idée des pré-calculs est de réduire le nombre de lignes à lire ou à poursuivre.

Une façon d'y parvenir consiste à utiliser une vue indexée et à laisser le moteur effectuer les calculs par lui-même. Comme ce type de vues présente certaines limites, vous finissez par créer un tableau simple et effectuez les calculs à la place. Fondamentalement, cela dépend des besoins de l'entreprise.

Ainsi, dans l'exemple ci - dessous , je suis en train de créer une table RowIDet des RowDatetimecolonnes et insérer 1 million de lignes. J'utilise une vue indexée pour compter les entités par jour, donc au lieu d'interroger 1 million de lignes par an, je vais interroger 365 lignes par an pour compter ces mesures.

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

Le succès d'une telle solution dépend beaucoup de la façon dont les données sont distribuées et du nombre de lignes dont vous disposez. Par exemple, si vous avez une entrée par jour pour chaque jour de l'année, la vue et le tableau auront la même correspondance de lignes, de sorte que les opérations d'E / S ne seront pas réduites.

En outre, ce qui précède n'est qu'un exemple de matérialisation des données et de leur lecture. Dans votre cas, vous devrez peut-être ajouter plus de colonnes à la définition de la vue.

gotqn
la source
0

J'utiliserais une table de recherche "Dates" pour joindre mes données à un index sur DatesId. J'utilise les dates comme filtre lorsque je souhaite parcourir les données historiques. La jointure est rapide et donc le filtrage car le DatesId est un index primaire en cluster (clé primaire). Ajoutez également la colonne de date (en tant que colonne incluse) pour votre tableau de données.

Le tableau des dates comprend les colonnes suivantes:

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

Exemple de données: 20310409 2031-04-09 2031 2 2031-Q2 4 avril avr 2031_15 15 99 9 3 mercredi

Vous pouvez m'envoyer un PM si vous voulez un fichier csv de cette façon afin que vous puissiez l'importer dans la base de données, mais je suis sûr que vous pouvez facilement trouver quelque chose comme ça en ligne et créer le vôtre.

J'ajoute également une colonne d'identité afin que vous puissiez obtenir un entier pour chaque date. Cela rend le travail un peu plus facile, mais pas obligatoire.

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

Cela me permet de revenir facilement à une certaine période. Il est assez facile de créer vos propres vues à ce sujet. Vous pouvez bien sûr également utiliser la fonction ROW_NUMBER () pour cela pendant des années, des semaines, etc.

Une fois que j'ai la plage de données que je veux, je me joins aux données. Fonctionne très vite!

starbyone
la source
0

Étant donné que vous regroupez toujours des valeurs sur la base d'un nombre entier de mois, je voudrais d'abord regrouper par mois dans une sous-requête dans la clause from. Cela revient à utiliser une table temporaire. Je ne sais pas si cela accélérerait réellement votre requête.

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
Jeremy Lakeman
la source
-2

Pour améliorer la vitesse de la requête SQL, vous devez ajouter des index. Pour chaque table jointe, vous devez ajouter un index.

Comme cet exemple de code pour oracle:

CREATE INDEX supplier_idx
ON supplier (supplier_name);
user12467638
la source
ce n'est pas une mauvaise suggestion. vous voyez dans l'OP qu'une table temporaire est créée sans index - INNER JOIN #Temp e sur c.col7 = e.id. bien qu'il y ait matière à amélioration dans la réponse, je ne pense pas qu'elle devrait être diminuée en masse. en particulier pour un nouvel utilisateur.
smoore4
@ smoore4 D'accord, cette option de downvoting sans argument clair doit être supprimée. Il y a une grosse mauvaise utilisation de cette fonctionnalité
Greggz