2012-03-28 6 views
0

Ich bin mit SQL Server 2008.Warum führt meine gespeicherte Prozedur alle Auswahlvorgänge unabhängig von der Bedingungslogik aus?

Ich habe ein interessantes Szenario, in dem eine gespeicherte Prozedur (durch einen „Power-User“ geschrieben) eine okaye Laufzeit (ca. 4 Sekunden) hat, wenn es Daten ist in der Primärtabelle. Wenn der Suchwert nicht vorhanden ist, beträgt die durchschnittliche Laufzeit etwa 3 Minuten. Aufgrund der Funktionsweise des Prozesses und der Webanwendung, die die Prozedur verwendet, ist bei fehlenden Daten eine leere Ergebnismenge erforderlich.

Ich habe die Logik unten mit Werten getestet, die Daten und Werte haben, die nicht und der Fluss scheint zu funktionieren; Wenn ich jedoch meine eigentliche Abfrage in die else-Anweisung lege, scheint es, als ob dieser Teil immer ausgewertet wird, obwohl ich weiß, dass die logische Verzweigung nicht ausgeführt werden sollte.

DECLARE @spId int 

SELECT @spId = td.mainId 
FROM dbo.PRIMARYTABLE 
WHERE td.longId = @searchVal 

IF @spId < 1 OR @spId IS NULL 
BEGIN 
    select 'RETURN EMPTY RESULT SET' as test 
END 
ELSE 
BEGIN 
    SELECT 'DO ACTUAL QUERY' as test 
END 

Wenn ich teste dies mit einem Blindwert, wie beispielsweise 1111, das select 'RETURN RESULT SET EMPTY' als Testzurückgeführt wird. Wenn ich einen Wert verwende, von dem ich weiß, dass er existiert, wird die SELECT 'DO ACTUAL QUERY' als Test zurückgegeben. Wenn ich "SELECT 'DO ACTUAL QUERY' als Test" mit der eigentlichen Heavy-Duty-Abfrage ersetze und den gleichen nicht vorhandenen Dummy-Wert verwende, sieht es immer noch so aus, als wäre die ELSE-Klausel erreicht.

Was fehlt mir hier?

+0

Sie sagten "sieht so aus", also sind Sie sich nicht sicher? Was ist Ihre "Heavy Duty" -Abfrage? Der von Ihnen gepostete Code ist nicht vollständig (z. B. fehlender Alias, Variablendeklaration), sodass Sie möglicherweise etwas anderes mit Ihrer "Heavy Duty" -Abfrage machen.I ** bezweifle, dass du die ELSE-Klausel mit nicht zufriedenstellenden Kriterien getroffen hast –

+0

Die "Heavy Duty" -Abfrage ist eine Ungeheuerlichkeit, bei der Casts, Round & IsNulls für eine Reihe von Berechnungen verwendet wurden. Ich weiß nicht, ob es eine gespeicherte Sql-Server-Prozedur-Mechanik gibt, mit der ich nicht vertraut bin, aber in meinen Tests erschien die if/else-Bedingungslogik einwandfrei; Es scheint jedoch immer noch so, als würde der else-Teil aufgerufen, wenn er aus dem Code heraus ausgeführt wird (entweder über sql management studio oder asp.net mvc web application). – jason

+0

nur "leicht" ersetzen Mit "havy duty" wählen würde man den IF ... ELSE-Ablauf nicht ändern. Es ist sehr wahrscheinlich, dass Ihre IF-Bedingung (gelesene @ spId-Variable) einen "unerwarteten Wert" erhält. Nikolas Antwort kann Ihnen einen guten Ausgangspunkt bieten. ** Das letzte Ding ** wäre zu denken, dass mit * @ spId <1 oder null * du irgendwie ELSE Block schlagen kannst. –

Antwort

1

Vielleicht zeigen Sie nicht alles. Es gibt eine kontraintuitive Aussage über die Zuweisung in select, bei der keine Zeilen zurückgegeben werden - der Wert der Variablen wird nicht gelöscht. Fügen Sie diese in SSMS:

declare @searchVal as int 
set @searchVal=111 

DECLARE @spId int 
set @spId = 2134 
SELECT @spId = td.mainId 
FROM (select 839 as mainId, 0 as longid) td 
where td.longId = @searchVal 
print @spid 

@spid wird 2134. Aus diesem Grund sollten Sie immer prüfen, mit @@ rowcount, in Ihnen Fall

IF @@rowcount = 0 or @spId < 1 or @spId is null 
BEGIN 
    select 'RETURN EMPTY RESULT SET' as test 
END 
ELSE 
BEGIN 
    SELECT 'DO ACTUAL QUERY' as test 
END 

Es gibt auch eine Möglichkeit von duplizierten Daten von longId , zufällige mainid aus Zeilen zurückgeben, die @searchval-Bedingung erfüllen.

Ansonsten würde ich nicht wissen.

+1

Das Ändern der Auswahl in 'select @spId = max (td.MainId)' würde ebenfalls funktionieren, da dann immer eine Zeile zurückgegeben wird und Null ist, wenn kein übereinstimmender Datensatz gefunden wird. Wenn 'longId' eine eindeutige Integritätsbedingung aufweist, sollte SQL Server einen Plan generieren, der den Wert des zugeordneten Index nachschlägt. –

0

Vielen Dank für Ihre Anregungen. Ich entschuldige mich für das Fehlen der gesamten gespeicherten Prozedur, aber ich darf diesen genauen Code nicht teilen. Der Ausschnitt, mit dem ich anfing, war Pseudo-Code (nun, echter Code mit umbenannten Tabellen und Feldern).

Ich denke, Nikola Markovinović kann auf etwas mit seiner Antwort und Artikellink sein. Diese ganze Tortur war irgendwie verrückt. Ich googelte, debuggte, und machte das Ganze noch einmal, dann Suche auf Stapelüberlauf. Nach ein paar Änderungen von Ihren Vorschlägen, fing das Verfahren magisch an, mit der Laufzeit zu reagieren, die ich dachte, dass es sollte. Ich glaube nicht, dass einige der ursprünglichen Änderungen vorgenommen wurden oder dass sie nicht von SQL Server korrekt zwischengespeichert wurden. Ich habe nichts als Vermutungen.

Es ist sehr seltsam, weil es für eine gute Stunde oder mehr lief, als ob es nie geändert worden wäre (Leistung weise) ... dann trat es gerade in Gang. Ich frage mich, ob das nicht meine Schuld ist und vielleicht änderte ich nicht die Inszenierung, wie ich es bei Test gemacht habe ... das scheint die machbarste Erklärung zu sein.

Wie auch immer, danke für Ihre Vorschläge. Ich habe ein paar Dinge gelernt, das ist immer gut.