2017-02-20 4 views
0

Der Schlüssel dieser Frage ist "Optimal", was die schnellste Rückkehrzeit bedeutet. Ich habe ein paar Tabellen mit Informationen, von denen ich Stücke haben möchte. Ich habe keine Probleme, die Abfrage selbst zu schreiben, nur um herauszufinden, wie der schnellste Weg, um die Informationen zu bekommen wäre.So erhalten Sie Datensätze aus mehreren Tabellen optimal

  • Audit (Dies ist die primäre Tabelle I von Informationen wollen)
  • Order (Der Rest sind Tabellen I von begrenzten Daten wollen)
  • Jobs
  • Credits

Die Sache, die sie Gemeinsam ist ein Konto und somit eine AccountID. Ich habe die AccountID, nach der ich im Voraus suche. Leider hat die Audit-Tabelle keinen direkten Fremdschlüssel in der betreffenden Account-Tabelle, und um zu bestimmen, ob der Audit-Datensatz zu meiner Ergebnismenge gehört, müsste ich der Audit-Tabelle und den nachfolgenden 3 Tabellen nacheinander beitreten Überprüfen Sie, ob der Audit-Datensatz sich auf meine AccountID bezieht.

Zum Beispiel

Select a.* from [Audits] a JOIN [Orders] o ON a.RecordID = o.OrderID 
where a.RecordType = 'Order' and o.AccountID = @AccountID 
union 
select a.* from [Audits] a JOIN [Jobs] j on a.RecordID = j.JobID 
where a.RecordType = 'Job' and j.AccountID = @AccountID 
... 

Ich beabsichtige, ein nächste auf der ersten Teilmenge von Daten zu tun holen und dann in den Informationen aus den sekundären Tabellen zu füllen, so dass ich zunächst einen begrenzten Erfolg zu tun. Ich sehe das als ein zweiteiliges Problem, zuerst der schnellste Weg, die AuditIDs zu finden, die zu meiner Teilmenge gehören, und zweitens den schnellsten Weg, um die fehlenden Daten auszufüllen. Irgendwelche Vorschläge würden geschätzt werden.

EDIT 1

Ich habe jetzt mit einer Lösung zu kommen, aber ich würde daran interessiert zu wissen, ob es irgendwelche einfache Möglichkeiten, es zu optimieren, sind so hier in Ich werde es posten hofft, es hilft weiter das Problem zu klären. Wenn Sie Syntaxfehler bemerken, ignorieren Sie sie bitte einfach. Ich versuche so viele unnötige Informationen wie möglich zu entfernen.

Create Table #AuditTemp (columns) 
Insert into #AuditTemp a.*, null as [Extra1], null as [Extra2] ... 
From [Audits] a 
Left Join [Orders] o ON a.RecordID = o.OrderID 
Left Join [Jobs] j ON a.RecordID = j.JobID 
Left Join [Credits] c ON a.RecordID = c.CreditID 
Where o.AccountID = @AccountID or j.AccountID = @AccountID ... 
Order By Time desc 
OFFSET @offset ROWS FETCH NEXT @PageSize ROWS ONLY 

Update #AuditTemp Set [Extra1] = o.[Column1] ... 
From [Orders] Where o.AccountID = @AccountID and #AuditTemp.RecordID = o.OrderID 
... 

So bekomme ich die 20 Datensätze, die ich brauche, und sie dann zu einem Zeitpunkt in einem füllen, wenn sie zusammenpassen.

+0

Lassen Sie mich sehen, wenn ich es richtig mache: das 'RecordID' Feld aus der' Audit' Tabelle kann entweder eine Bestellung, ein Job oder eine Gutschrift sein, und das einzige, was sie gemeinsam haben, ist das 'AccountID' Feld? –

+1

Das sieht ... Spaß aus. Die eine Sache, die mir in den Sinn kommt, ist die Verwendung von "union all" anstelle von "union". Das wird die zusätzliche Sortierung und Deduplizierung von "union" auslassen. – SqlZim

+0

Welche Version & Edition von SQL Server verwenden Sie? 'select @@ version' – SqlZim

Antwort

1

Wenn dies etwas ist, das Sie ständig tun müssen, werde ich das Erstellen eines view aus Ihren Sekundärtabellen vorschlagen, und verwenden Sie es, um Ihre Audit Tabelle mit Ihren sekundären Tabellen zu verbinden.

CreateView [dbo].[SecondaryTables] 
AS 
SELECT OrderID AS RecordID, 'Order' AS RecordType, AccountID 
FROM [Orders] 
UNION 
SELECT JobID AS RecordID, 'Job' AS RecordType, AccountID 
FROM [Jobs] 
UNION 
SELECT CreditID AS RecordID, 'Credit' AS RecordType, AccountID 
FROM [Credits] 

Dann können Sie diese Ansicht verwenden, um alle Daten, die Sie

SELECT [all your required fields] 
FROM [SecondaryTables] vw 
INNER JOIN [Audit] au 
ON vw.RecordID = au.RecordID AND vw.RecordType = au.RecordType 
LEFT OUTER JOIN [Orders] od 
ON vw.RecordID = od.OrderID AND vw.RecordType = 'Order' 
LEFT OUTER JOIN [Jobs] jo 
ON vw.RecordID = jo.JobID AND vw.RecordType = 'Job' 
LEFT OUTER JOIN [Credits] cr 
ON vw.RecordID = cr.CreditID AND vw.RecordType = 'Credit' 
WHERE vw.AccountID = @AccountID 

müssen sich registrieren Wenn Sie die Ergebnisse aus allen Tabellen erwarten (alle Ihre Ergebnisse werden immer auch Daten aus den drei Tabellen), Sie kann die LEFT OUTER zu INNER ändern, um die Leistung zu verbessern.

1

Das erste, was ich tun würde, ist, den Ausführungsplan für die Abfrage zu betrachten. Eine mögliche Alternative wäre wie unten gezeigt.

SELECT A.* 
FROM [Audits] A 

INNER JOIN (
    SELECT OrderID AS RecordID FROM [Orders] WHERE AccountID = @AccountID 
    UNION ALL 
    SELECT JobID AS RecordID FROM [Jobs] WHERE AccountID = @AccountID 
) AS DT 
ON A.RecordID = DT.RecordID 
WHERE A.RecordType IN ('Order','Job') 

Eine weitere Alternative ist, die UNION ALL-Abfrage in einen allgemeinen Tabellenausdruck zu verschieben.

Der SQL Server-Optimierer ist in diesen Tagen ziemlich gut. Es ist leicht, die Abfrage zu finden, die am wenigsten kostet, aber das ist nicht die gleiche Sache wie die schnellste.

Wenn Sie in der Regel nur sehr wenige Aufträge oder Aufträge für ein Konto haben, werden Sie nur sehr wenigen Datensätzen beitreten und nur einmal statt zweimal wie im Original beitreten.

Betrachten Sie die Selektivität des RecordType in der Tabelle [Audits]. Wenn Auftrag und Job die Mehrzahl Ihrer Datensätze umfassen, hat das Hinzufügen eines Indexes für RecordType wenig Vorteile. Vermutlich haben Auftrag und Jobs einen Index gegen AccountID?

Sie sollten im Schema für Ihre Tabellen explizit angegeben werden. dbo.Audits, Sales.orders usw. Es ist nur eine Sache weniger, die die Abfrage-Engine zur Laufzeit vergleichen muss.

Leistungstests auf SQL Server können in einer gemeinsam genutzten Umgebung ein wenig schmerzhaft sein. Ich finde mit SQL Profiler gibt einen guten Hinweis, was sowohl für meine Abfrage und was sonst noch läuft zu tun, und es wird Ihnen alle gewünschten Zeiten geben.

Wenn Sie testen, wenn der Server ruhig ist, denken Sie daran, dass DBCC DROPCLEANBUFFERS den Puffercache nach jedem Lauf ausspült, damit Sie eine eindeutige Ansicht darüber erhalten, wie die Abfrage von Cold ausgeführt wird.

Wenn Ihre Produktion Box eine andere Spezifikation als Ihre Test-Box ist, dann sind Sie auf ein Verstecken zu nichts. Ein Multicore-Server mit großen Mengen an RAM und gemeinsam genutztem Speicher wird sich anders als eine typische DEV-Workstation entwickeln, insbesondere wenn Sie mehrere Aufgaben gleichzeitig ausführen.

Verwandte Themen