2009-03-13 6 views
3

Ich habe die folgende Abfrage eine Abfrage in einer bestimmten ReihenfolgeWie kann ich SQL Server zwingen

  
DECLARE @userId INT 
DECLARE @siteId INT 

SET @siteId = -1 
SET @userId = 1828 

SELECT a.id AS alertId, 
     a.location_id, 
     a.alert_type_id, 
     a.event_id, 
     a.user_id, 
     a.site_id, 
     a.accepted_by 
FROM alerts AS a  
JOIN alert_types AS ats ON a.alert_type_id = ats.id 
JOIN events AS tr ON a.event_id = tr.event_id 
WHERE tr.end_Time IS null 
AND  tr.status_id = 0 
AND  ats.code = 'E' 
AND  a.site_id in (SELECT * FROM dbo.udf_get_event_sitelist(@siteId, @userId)) 

auszuführen

Diese Abfrage dauert zwischen 5 und 17 Sekunden zu laufen, aber unter vielen Umständen die Funktion dbo.udf_get_event_sitelist (@siteId, @userId) gibt keine Zeilen zurück, daher findet die Abfrage keine Daten.

Wie kann ich SQL Server zwingen, die benutzerdefinierte Funktion zuerst auszuführen. Ich schätze, dass ich die Abfrage in eine gespeicherte Prozedur umschreiben und die Unterauswahl zuerst ausführen könnte, jedoch möchte ich es in einer einzigen SQL-Anweisung tun, wenn möglich.

+0

Können Sie den Code aus dem UDF zu bitte posten, ich vermute, dass Sie besser dran sein kann wieder- Schreiben dieser Logik, vielleicht als Unterabfrage oder CTE. –

+0

Ich sehe hier keinen gespeicherten Prozess, nur eine Abfrage und eine Funktion. Sind diese INNER, OUTER oder CROSS Joins? – StingyJack

+0

Sie sind INNER JOINS (der Standard, wenn der Join-Typ nicht angegeben ist) –

Antwort

4

machen die „FROM“ Tabelle sind die von der Funktion gesetzt Ergebnisse und kommen Sie mit den anderen Tabellen es

DECLARE @userId INT 
DECLARE @siteId INT 

SET @siteId = -1 
SET @userId = 1828 

SELECT a.id AS alertId, 
     a.location_id, 
     a.alert_type_id, 
     a.event_id, 
     a.user_id, 
     a.site_id, 
     a.accepted_by 
FROM (SELECT * FROM dbo.udf_get_event_sitelist(@siteId, @userId)) dt 
JOIN alerts AS a ON dt.site_id=a.site_id 
JOIN alert_types AS ats ON a.alert_type_id = ats.id 
JOIN events AS tr ON a.event_id = tr.event_id 
WHERE tr.end_Time IS null 
AND  tr.status_id = 0 
AND  ats.code = 'E' 
+0

Danke Mike. Ich hatte selbst die selbe Lösung, hatte sie aber noch nicht aufgeschrieben. Aus Interesse hat dies die Zeit für die Mehrheit der Abfragen von 5-15 Sekunden auf unter eine Sekunde –

+0

+1 für einen anderen Weg, in Zeile und nicht RBAR geändert. Netter Mike! – StingyJack

3

Sie könnten die Ergebnisse der udf_get_event_sitelist in eine Tabelle Variable auswählen und nur mit dem großen Abfrage vorgehen, wenn @@ rowcount> 0

0

Außerdem benötigen Sie UDF, um nur die SITE_ID zurück, wie ich Ihnen raten, neet nicht Spalten alle (*)

SELECT * FROM dbo.udf_get_event_sitelist(@siteId, @userId) 

zu

SELECT site_id FROM dbo.udf_get_event_sitelist(@siteId, @userId) 
+0

Ich nehme an, die UDF gibt nur eine Spalte zurück, sonst dies wäre nicht gültig? Ich stimme zu, dass es klarer aussehen würde, wenn die Spalte angegeben wäre (und verhindert, dass die Abfrage unterbrochen wird, wenn die benutzerdefinierte Funktion später geändert wird, um mehrere Spalten zurückzugeben). –

+0

Nicht nur würde es klarer aussehen, aber es würde bessere Praktiken fördern. Wenn Sie den fehlenden JOIN-Typ angeben, ist dies definitiv eine gute Sache, um darauf hinzuweisen. – StingyJack

+0

Wird es als gute Praxis angesehen, immer implizite Join-Typen anzugeben? Ich bin mir bewusst, dass ein INNER JOIN der Standardtyp ist, aber ich gebe den JOIN-Typ nicht als den Standardtyp an. Genauso verwende ich selten SORT ASCENDING, wie es impliziert ist. –

2

Das Problem, das Sie haben, wenn Funktionen inline ist, dass sie für jede Zeile retur neu bewertet werden können ned im SELECT. Das bedeutet, wenn die SELECT-Anweisung 100 Zeilen zurückgibt, kann die Funktion 100 Mal ausgeführt werden.

Sie sollten Sambo99s Ratschlag wirklich befolgen und ihn in eine Tabellenvariable (oder eine temporäre Tabelle, wenn Sie denken, dass sie Indizes benötigt) extrahieren.

+0

Ich habe angenommen, dass, da ich die Sub-Abfrage nicht mit der äußeren Abfrage korreliert hatte, SQL Server diese Bedingung zuerst bewerten würde, wie viele andere Datenbank-Engines). Ich nehme an, ich habe falsch angenommen. –

+0

Es kann so oder so passieren, also sagt blind, auf die eine oder andere Art zu gehen, dass der Optimierer den Plan annimmt. Ich denke, es ist besser, auf jeden Fall explizit zu sein, wo es in beide Richtungen gehen könnte. – StingyJack