C# -Programmierer hier und ich habe beauftragt, eine lange SQL Server-Prozedur in einer unserer alten Anwendungen zu bearbeiten, die so leistungsorientiert und effizient wie möglich ausgeführt werden muss. Ich würde mich über eine Bestätigung freuen, wenn meine Route die beste für das vorliegende Szenario ist.SQL Server: Hilfe zu optimieren meine Abfrage
SZENARIO
Es ist ein unorthodoxer ein aufgrund der Konstruktion sowohl Code und DB weise von den ursprünglichen Designern. Für ein Suchraster muss ich in tbl.docs
sehen, ob ein "Garantiedokument" generiert wurde oder nicht, basierend auf der vom Benutzer gewählten Option und dem Verkettungswert des Strings/Wortes "Warranty" und dem tbl.warranty.warrantyId
Wert selbst.
Dieser Wert von 'Garantie' + tbl.warranty.warrantyId
entspricht dem tbl.docs.name
Spaltenwert und erscheint leider meine einzige Möglichkeit, die beiden Tabellen beizutreten/zu verbinden.
Garantie-Dokumente können mehrmals pro Garantie generiert werden.
Parameter @IsGenerated
ist die Benutzeroption, die der Endbenutzer auswählt, um die Filterung zu aktivieren oder nicht.
Hier einige bevölkerten Daten zur Erläuterung:
tbl.warranty
:
| warrantyId | name | createdDate |
|------------|-------------|-------------------------|
| 456 | Warranty 1 | 2002-04-01 12:14:53.330 |
| 1000 | Warranty 2 | 2002-04-01 12:14:53.327 |
| 1701 | Warranty 3 | 2002-04-01 12:14:53.333 |
| 2456 | Warranty 4 | 2002-04-01 12:14:53.327 |
| 3556 | Warranty 5 | 2002-04-01 12:14:53.330 |
tbl.docs
:
| docId | name | createdDate |
|------------|--------------|-------------------------|
| 1 | Warranty1000 | 2006-11-25 13:33:31.093 |
| 2 | Warranty456 | 2015-02-11 13:33:31.100 |
| 3 | Warranty1000 | 2012-05-17 13:33:31.097 |
| 4 | Warranty1000 | 2017-01-11 13:33:31.097 |
| 5 | Warranty1701 | 2017-03-14 13:33:31.100 |
| 6 | Warranty456 | 2017-03-15 13:33:31.100 |
So können Sie sehen:
- warrantyId 1000 ha s dreimal erzeugt worden
- warrantyId 456 zweimal erzeugt wurde
- Garantien mit warrantyIds 3556 und 2456 wurden überhaupt nicht erzeugt, so weiter ...
gewünschte Aktion (en)/RESULT (s)
Benutzer kann wählen, keine Filteroptionen zu wählen, [Ich muss alle Garantiesätze und die erzeugte Zeit (tbl.docs.createdDate) anzeigen, aber mit einem Null tbl.docs.createdDate (generateddate wenn Sie), wenn es nie angefordert worden ist, um zu erzeugen, oder der JÜNGSTE Rekord, der auf MA basiert x tbl.docs.createdDate (generatedDate), wenn es]
| warrantyId | name | generatedDate |
|------------|--------------|-------------------------|
| 456 | Warranty 1 | 2017-03-15 13:33:31.100 |
| 1000 | Warranty 2 | 2017-01-11 13:33:31.097 |
| 1701 | Warranty 3 | 2017-03-14 13:33:31.100 |
| 2456 | Warranty 4 | NULL |
| 3556 | Warranty 5 | NULL |
Benutzer auf Garantien filtern kann, hat die Dokumentation für generiert wurden, [ich alle Garantie Aufzeichnungen anzeigen müssen, dass ein doc Rekord auf der Basis haben Zeichenfolge/Wort "Garantie" und die Garantie-ID entspricht dem Wert von docs.name. Garantien, die mehrere Dokumente erzeugt haben, ich brauche nur das jüngste Rekord erzeugt]
| warrantyId | name | generatedDate |
|------------|--------------|-------------------------|
| 456 | Warranty 1 | 2017-03-15 13:33:31.100 |
| 1000 | Warranty 2 | 2017-01-11 13:33:31.097 |
| 1701 | Warranty 3 | 2017-03-14 13:33:31.100 |
Benutzer filtern können auf Garantien, die Dokumente sind nicht für generiert wurde, [Ich brauche alle Garantie Datensätze anzuzeigen, die haven‘ t hatte einen doc-generierten Datensatz basierend auf der Zeichenkette/dem Wort "Warranty" und der WarrantyId-gleichwertigen Dokumentation.name]
| warrantyId | name | generatedDate |
|------------|--------------|-------------------------|
| 2456 | Warranty 4 | NULL |
| 3556 | Warranty 5 | NULL |
Das ist mein Stab an sie. Ich habe mir gedacht, eine temporäre Tabelle basierend auf der Docs-Tabelle zu erstellen und diese in meiner Abfrage zu verwenden, ist der beste Weg für Effizienz und vermeidet, dass diese Abfrage mehr als das, was bereits ist, unterdrückt wird.
IF OBJECT_ID('tempdb..#tmpDocs') IS NOT NULL
DROP TABLE #tmpDocs
GO
CREATE TABLE #tmpDocs
(
createdDate datetime not null,
name varchar(30) not null
)
INSERT INTO #tmpDocs (createdDate, name)
SELECT createdDate, name
FROM docs
DECLARE @IsGenerated BIT
SET @IsGenerated = 0
SELECT
w.warrantyId,
w.name,
(SELECT TOP 1 d.createdDate
FROM #tmpDocs d
WHERE d.name = CONCAT('Warranty', w.warrantyId)
ORDER BY d.createdDate DESC) AS [generatedDate]
FROM
warranty w
WHERE
(@IsGenerated IS NULL OR @IsGenerated = 0
OR EXISTS (SELECT *
FROM #tmpDocs d
WHERE d.name = CONCAT('Warranty', w.warrantyId)))
AND (@IsGenerated IS NULL OR @IsGenerated = 1 OR
NOT EXISTS (SELECT *
FROM #tmpDocs d
WHERE d.name = CONCAT('Warranty', w.warrantyId)
)
)
)
EDITED - VERSUCH # 2
select
w.warrantyId,
w.name,
d.createdDate as [generatedDate]
from warranty w
left join #tmpDocs d
on d.name = concat('Warranty', w.warrantyId)
AND d.createdDate = (SELECT top 1 d.createdDate
FROM #tmpDocs d
WHERE d.name = CONCAT('Warranty', w.warrantyId)
ORDER BY d.createdDate desc)
WHERE
(@IsGenerated IS NULL OR @IsGenerated = 0
OR EXISTS (SELECT *
FROM #tmpDocs d
WHERE d.name = CONCAT('Warranty', w.warrantyId))
)
AND (@IsGenerated IS NULL OR @IsGenerated = 1
OR NOT EXISTS (SELECT *
FROM #tmpDocs d
WHERE d.name = CONCAT('Warranty', w.warrantyId)
)
)
group by w.warrantyId, d.createdDate, w.name
Die Ausführungszeiten sind die gleichen aber ich nehme an, weil meine kleine Datenmenge I mit gerade arbeite:
(5 Zeile (n) betroffen)
Ausführungszeit des SQL-Servers: CPU-Zeit = 0 ms, verstrichene Zeit = 0 ms.
(5 row (s) affected)
SQL Server-Ausführungszeiten: CPU-Zeit = 0 ms, verstrichene Zeit = 0 ms.
Vielen Dank für das Lesen und so weiter. Wenn es eine alternative Route gibt (ohne CTE, da dies nur ein einfacher Aspekt des Prozesses ist, den ich bearbeiten werde, habe ich nicht die Zeit, das Ganze zu refaktorisieren zu der Zeit), würde ich sehr offen sein, es zu hören. Die Ausführung dieses Verfahrens kann es sich nicht leisten, stecken zu bleiben.
Ich schätze die Antwort sehr. Ich kann die Struktur der Tabelle nicht bearbeiten, da mehr als nur Garantiedokumente generiert werden usw. All dies filtert durch den gespeicherten Prozess, und das Bearbeiten des Entwurfs/Arbeitsablaufs von diesem über die Anwendungsseite würde es über die zugewiesene Zeit hinaus dauern für dieses Projekt gegeben. Ich bin im Grunde gezwungen, mit der Struktur vor Ort zu arbeiten. – theoryTim
Nicht sicher, wie viele SPs Sie arbeiten, aber die obige Abfrage sollte Ihnen die Ergebnisse, die Sie suchen. in Ihren Ergebnissen suchten Sie nur nach dem neuesten Dokument, oder wollten Sie eine Garantie pro Dokument haben? – Vee
Ist es auch möglich, Indizes für die Tabellen zu ändern? Sie haben diese in der ursprünglichen Frage nicht erwähnt, und der schlechte/gute/gute Index ist normalerweise der beste Ort, um mit der Optimierung zu beginnen. – Vee