SQL Server: la requête s'exécute très lentement (jusqu'à 20 secondes)

Je viens ici maintenant avec un problème avec "ma" requête de database. Il s'exécute pendant environ 22-25 secondes sur une database "froide" et je cherche désespérément un moyen de l'améliorer.

J'aimerais ignorer toutes les suggestions liées à la table simplement parce que je ne peux pas changer sa structure (dommage). J'ai ce qui m'a été donné et bien … J'essaie juste de find une solution pour améliorer les performances de cette requête. Je suis conscient que la database n'est pas bien conçue, mais pour le moment je ne peux rien y faire, donc je vais accepter s'il n'y a aucun moyen d'améliorer la requête.

SET STATISTICS IO ON; SET STATISTICS TIME ON; SET STATISTICS PROFILE ON; SELECT <STUFF TO SELECT> FROM [dbo].[2009_Zlecenia] AS Z OUTER APPLY (SELECT TOP 1 M1.DataDo AS 'DataRozladunku', M1.Kod, M1.Miasto, MK1.Skrot FROM [dbo].[MiejscaZaladunkuRozladunku] AS M1 LEFT JOIN [dbo].[Kraje] AS MK1 ON M1.Kraj = MK1.Id WHERE M1.Zlecenie = Z.Id AND M1.Rodzaj = 2 ORDER BY Data DESC) AS MZR OUTER APPLY (SELECT TOP 1 M2.DataDo AS 'DataZaladunku', M2.Kod, M2.Miasto, MK2.Skrot FROM [dbo].[MiejscaZaladunkuRozladunku] AS M2 LEFT JOIN [dbo].[Kraje] AS MK2 ON M2.Kraj = MK2.Id WHERE M2.Zlecenie = Z.Id AND M2.Rodzaj = 1 ORDER BY Data ASC) AS MZR1 OUTER APPLY (Select count(FP1.Id) 'Count' FROM [dbo].[2009_FakturyPrzewoznika] AS FP1 WHERE FP1.ZlecenieId = Z.Id group by FP1.ZlecenieId) AS FP OUTER APPLY (SELECT count(FP3.ZlecenieId) 'Count' FROM [dbo].[2009_FakturyPrzewoznika] AS FP3 WHERE FP3.ZlecenieId IN (Select Id FROM [dbo].[2009_Zlecenia] WHERE IdZlecenieNadrzedne <> 0 And IdZlecenieNadrzedne = Z.Id) GROUP BY FP3.ZlecenieId) AS FP2 OUTER APPLY (SELECT TOP 1 Nr FROM [dbo].[2009_KartyDrogowe] AS KD1 LEFT JOIN [dbo].[ZleceniaKartyDrogowej] AS ZKD1 ON ZKD1.KartaDrogowa = KD1.Id WHERE ZKD1.Zlecenie = Z.Id) AS KD OUTER APPLY ( Select count(Id) 'Count' FROM [dbo].[2009_Zlecenia] WHERE IdZlecenieNadrzedne <> 0 And IdZlecenieNadrzedne = Z.Id) AS ZP LEFT JOIN [dbo].[ZleceniaWalutaObca] AS ZWO ON Z.Id = ZWO.OrderId LEFT JOIN [dbo].[Kraje] AS K1 ON Z.TransportZ = K1.Id LEFT JOIN [dbo].[Kraje] AS K2 ON Z.TransportDo = K2.Id LEFT JOIN [dbo].[Lista] AS L1 ON Z.Status = L1.Id LEFT JOIN [dbo].[Uzytkownicy] AS U ON Z.Uzytkownik = U.Id LEFT JOIN [dbo].[Oddzialy] AS UO ON U.Oddzial = UO.Id LEFT JOIN [dbo].[FakturyZlecen] AS FZ ON FZ.Zlecenie = Z.Id LEFT JOIN [dbo].[FakturyZlecen] AS FZ1 ON FZ1.Zlecenie = Z.IdZlecenieNadrzedne LEFT JOIN [dbo].[2009_Faktury] AS F1 ON FZ.Faktura = F1.Id LEFT JOIN [dbo].[2009_Faktury] AS F2 ON FZ1.Faktura = F2.Id LEFT JOIN [dbo].[Firmy] AS FO ON FO.Id = Z.ZleceniodawcaId LEFT JOIN [dbo].[Uzytkownicy] AS O1 ON FO.Opiekun1 = O1.Id LEFT JOIN [dbo].[Uzytkownicy] AS O2 ON FO.Opiekun2 = O2.Id LEFT JOIN [dbo].[Uzytkownicy] AS O3 ON FO.Opiekun3 = O3.Id WHERE Z.TypZlecenia = 4 AND Z.Importowane=0 ORDER BY YEAR(Z.DataZlecenia) DESC, Z.Idx DESC, Z.Nr DESC SET STATISTICS IO OFF; SET STATISTICS TIME OFF; SET STATISTICS PROFILE OFF; 

Je postrais un plan d'exécution, mais c'est assez gros. Je répondrai vivement à toutes les questions à ce sujet. 🙂

Environ 80% du time de requête est consommé par le sorting dans les clauses d'application externes.

Voici les statistics de l'exécution sur le server "hot":

(16467 ligne (s) affectée (s))

Tableau 'Uzytkownicy'. Nombre de balayages 0, lectures logiques 33042, lectures physiques 0, lectures en lecture anticipée 0, lectures logiques lob 0, lectures physiques lob 0, lectures lues en lecture anticipée 0.

Tableau 'Firmy'. Nombre de balayages 0, lectures logiques 50421, lectures physiques 0, lectures en lecture anticipée 0, lectures logiques lob 0, lectures physiques lob 0, lectures lues en lecture anticipée 0.

Tableau '2009_Faktury'. Nombre de balayages 0, lectures logiques 48577, lectures physiques 0, lectures en lecture anticipée 0, lectures logiques lob 0, lectures physiques lob 0, lectures lues en lecture anticipée 0.

Table "Table de travail". Nombre de balayages 0, lectures logiques 0, lectures physiques 0, lectures en lecture anticipée 0, lectures logiques lob 0, lectures physiques lob 0, lectures lues en lecture anticipée 0.

Tableau 'FakturyZlecen'. Nombre de balayages 32934, lectures logiques 101846, lectures physiques 0, lectures en lecture anticipée 0, lectures logiques lob 0, lectures physiques lob 0, lectures lues en lecture anticipée 0.

Tableau 'Oddzialy'. Nombre de balayages 1, lectures logiques 32935, lectures physiques 0, lectures en lecture anticipée 0, lectures logiques lob 0, lectures physiques lob 0, lectures lues en lecture anticipée 0.

Tableau 'Lista'. Nombre de balayages 0, lectures logiques 32934, lectures physiques 0, lectures en lecture anticipée 0, lectures logiques lob 0, lectures physiques lob 0, lectures lues en lecture anticipée 0.

Table 'Kraje'. Nombre de balayages 2, lectures logiques 65874, lectures physiques 0, lectures en lecture anticipée 0, lectures logiques lob 0, lectures physiques lob 0, lectures lues en lecture anticipée 0.

Tableau 'ZleceniaWalutaObca'. Nombre de balayages 1, lectures logiques 0, lectures physiques 0, lectures en lecture anticipée 0, lectures logiques lob 0, lectures physiques lob 0, lectures lues en lecture anticipée 0.

Table " Table de travail" . Nombre de balayages 65420, lectures logiques 450989 , lectures physiques 0, lectures en lecture anticipée 0, lectures logiques lob 0, lectures physiques lob 0, lectures lues en lecture anticipée 0.

Tableau '2009_Zlecenia'. Nombre d'parsings 32635, lectures logiques 84027, lectures physiques 0, lectures en lecture anticipée 0, lectures logiques lob 0, lectures physiques lob 0, lectures lues en lecture anticipée 0.

Tableau 'ZleceniaKartyDrogowej'. Nombre de balayages 1, lectures logiques 0, lectures physiques 0, lectures en lecture anticipée 0, lectures logiques lob 0, lectures physiques lob 0, lectures lues en lecture anticipée 0.

Tableau '2009_FakturyPrzewoznika'. Le nombre d'parsings 318, les lectures logiques 687, les lectures physiques 0, les lectures en lecture anticipée 0, les lectures logiques lobes 0, les lectures physiques lob 0, les lectures lues en lecture anticipée 0.

Tableau 'MiejscaZaladunkuRozladunku'. Nombre de balayages 2, lectures logiques 5670, lectures physiques 0, lectures en lecture anticipée 0, lectures logiques lob 0, lectures physiques lob 0, lectures lues en lecture anticipée 0.

Temps d'exécution SQL Server: time CPU = 1547 ms, time écoulé = 1771 ms.

J'ai mis en évidence la "table de travail" car je crois que c'est la principale raison d'une si mauvaise performance.

Des suggestions qui aideraient ??

@MODIFIER

Le plan d'exécution est ici:

AperçuExecPlanExecPlan2ExecPlan3

Le plan semble contenir beaucoup de index spools , qui est un opérateur où SQL Server crée un index temporaire dans tempdb. Au less pour ces cas l'index permanent devrait améliorer beaucoup la performance.

Lorsque vous select count(column) SQL Server calcule les valeurs non nulles de cette colonne. Lorsque select count(*) est utilisé, le nombre de lignes est calculé et SQL Server peut simplement effectuer une parsing d'index pour tout index.

Il est bon de vérifier les searchs de keys à partir du plan, et s'il existe de telles searchs où le nombre réel d'exécutions est élevé, l'ajout de ces colonnes comme champ inclus dans l'index supprime la search de key. Cela a un coût supplémentaire pour les insertions / mises à jour.

Le découpage de la grande requête en plusieurs parties peut également aider l'optimiseur à choisir un meilleur plan. Dans les requêtes avec plusieurs grandes tables, il est également possible que la création du plan de requête se termine par un dépassement de timeout entraînant de très mauvais plans. Cela peut être vu dans les propriétés du premier nœud du plan de requête ("Niveau d'optimization")

Vous devez définitivement vous débarrasser des sous-sélections. Ils sont exécutés chaque fois que vous itérez une ligne. Vous devriez essayer de les join à gauche ce qui ne sera pas facile car je vous vois les limiter en sélectionnant top 1.

La mauvaise performance est l'utilisation de sous-sélections.

Je ne connais pas la structure et ce que vous pouvez faire en un coup d'œil, mais peut-être que ce simple conseil vous amènera à votre solution.

Considérons une rangée qui est chargée.

  • Vous chargez la ligne depuis [2009_Zlecenia]
  • Vous chargez TOUT le sous-menu MZR,
  • tu sortings MZR
  • vous rincer toutes les lignes, mais le premier de MZR2
  • Vous chargez TOUT le sous-menu MZR2,
  • vous sortingez MZR2
  • vous rincer toutes les lignes, mais le premier de MZR2
  • Vous chargez TOUS les sous-éléments FP1,
  • vous sortinger FP1
  • vous rincer toutes les lignes, mais le premier de FP1
  • Vous chargez TOUS les sous-menus FP2,
  • vous sortez FP2
  • vous rincer toutes les lignes, mais le premier de FP2
  • Vous chargez TOUT le sous-menu KD,
  • vous sortingez KD
  • vous rincer toutes les lignes, mais le premier de KD
  • Vous chargez TOUS les sous-éléments ZP,
  • vous sortingez ZP
  • vous rincer toutes les lignes, mais le premier de ZP

Vous ne faites qu'une seule fois les 10 jointures gauches (fast), mais pensez aux données qui sont chargées pour chaque ligne par les sous-sélections. Ils sont nouveaux chargés chaque ligne.

Essayez également d' indexer les colonnes pour lesquelles vous filterz: http://www.1keydata.com/sql/alter-table-add-index.html Les index vont augmenter le time d'exécution de la memory et la perte du disque dur.