Dies ist nur ein Teil der Abfrage zählen helfen, aber es scheint der Engpass zu sein:Ich brauche meine SQL-Abfrage Verbesserung für das Ziehen eines aktuelles Dokument
SELECT CAST (CASE WHEN EXISTS
(SELECT 1
FROM dbo.CBDocument
WHERE (FirmId = R.FirmId) AND
(ContributionDate > DATEADD(m, -3, GETDATE())) AND
((EntityTypeId = 2600 AND EntityId = P.IProductId) OR
(EntityTypeId = 2500 AND EntityId = M.IManagerId)))
THEN 1 ELSE 0 END AS BIT) AS HasRecentDocuments
FROM dbo.CBIProduct P
JOIN dbo.CBIManager M ON P.IManagerId = M.IManagerId
JOIN dbo.CBIProductRating R ON P.IProductId = R.IProductId
JOIN dbo.CBIProductFirmDetail D ON (D.IProductId = P.IProductId) AND
(R.FirmId = D.FirmId)
CROSS APPLY (SELECT TOP 1 RatingDate, IProductRatingId, FirmId
FROM dbo.CBIProductRating
WHERE (IProductId = P.IProductId) AND (FirmId = R.FirmId)
ORDER BY RatingDate DESC) AS RD
WHERE (R.IProductRatingId = RD.IProductRatingId) AND (R.FirmId = RD.FirmId)
Es gibt eine Menge von anderen Spalten, die ich in der Regel ziehe zurück, dass die CROSS APPLY und die anderen verbindet. Das Bit, das ich optimieren muss, ist die Unterabfrage in der case-Anweisung. Diese Unterabfrage dauert 3 Minuten, um 119k Datensätze zurückzugeben. Ich weiß genug über SQL, um so weit zu kommen, aber es muss einen Weg geben, dies effizienter zu machen.
Das Kernstück der Abfrage besteht darin, ein Flag zurückzugeben, wenn das zugehörige Produkt Dokumente enthält, die innerhalb der letzten 3 Monate zum System hinzugefügt wurden.
Bearbeiten: Meine DB ist in Azure gehostet und der Datenbank-Tuning-Berater wird keine Verbindung herstellen. In Azure gibt es eine Tuning Advisor-Komponente, die jedoch nichts andeutet. Es muss einen besseren Ansatz für die Abfrage geben.
Edit: In einem Versuch, weiter zu vereinfachen und die Täter zu ermitteln, ich es schnitzte auf diese Abfrage nach unten: (Anstatt festzustellen, ob ein aktuelles Dokument existiert, es zählt nur die letzten docs.)
SELECT D.FirmId, P.IProductId,
,(SELECT COUNT(DocumentId) FROM dbo.CBDocument WHERE
(FirmId = D.FirmId) AND
(ContributionDate > DATEADD(m, -3, GETDATE())) AND
((EntityTypeId = 2600 AND EntityId = P.IProductId) OR
(EntityTypeId = 2500 AND EntityId = M.IManagerId))) AS RecentDocCount
FROM dbo.CBIProduct P
FULL JOIN dbo.CBIProductFirmDetail D ON D.IProductId = P.IProductId
JOIN dbo.CBIManager M ON M.IManagerId = P.IManagerId
That läuft in 3 Minuten, 53 Sekunden.
Wenn ich eine Variable deklarieren, das Datum zu speichern (DECLARE @Today DATE = GETDATE()
) und setze die Variable anstelle von GETDATE() in der Abfrage (DATEADD(m, -3, @Today)
), läuft es in 12 Sekunden.
Gibt es ein bekanntes Leistungsproblem mit GETDATE()? Soweit ich weiß, kann ich die Variable nicht in einer Ansichtsdefinition verwenden.
Gibt es ein Licht auf alles, was auf eine Lösung hindeuten könnte? Ich nehme an, ich könnte das Ganze in eine gespeicherte Prozedur umwandeln, aber dann muss ich auch den Anwendungscode anpassen.
Danke.
https://docs.microsoft.com/en-us/sql/tools/dta/tutorial-database-engine-tuning-advisor Machen Sie das und Sie können Glück haben und müssen nur einige neue Indizes hinzufügen – Will
Danke, @Will. Ich bin diesen Weg gegangen. Ich kann den DTA nicht mit meiner Datenbank in Azure verbinden, und Azures Optimierungsratgeber empfiehlt nichts. –
Wenn Sie die Datenbank abfangen und in eine lokale Instanz von SQL Server laden können, können Sie es trotzdem versuchen. Die Indizes würden sich in azurblau nicht unterscheiden, glaube ich. – Will