2016-06-29 6 views
0

Ich habe eine einfache Abfrage, die sehr schnell läuft (ca. 1 Sekunde), wenn ich einen Stringliteral in meiner WHERE Klausel, wie zum Beispiel:Variable vs Stringliteral Geschwindigkeit Disparität

select * 
from table 
where theDate >= '6/5/2016' 

jedoch diese Abfrage (das nicht wesentlich ist) läuft über 2 Minuten in:

declare @thisDate as date 
set @thisDate = '6/5/2016' 

select * 
from table 
where theDate >= @thisDate 

ich mit OPTION(RECOMPILE) versucht, so here vorgeschlagen, aber es tut nichts, um die Leistung zu verbessern. Die Spalte theDate ist eine Datetime, diese Datenbank wurde vor kurzem aus SQL Server 2005 migriert.

Es gibt keinen Index auf meiner theDate Spalte, und die Tabelle hat knapp über 1 Milliarde Zeilen. Es ist eine freigegebene Ressource und ich möchte nicht mit der Indizierung beginnen, ohne sicher zu sein, dass es hilft.

finde ich, dass unter Verwendung von Logik anstelle einer Variablen als String die gleiche Leistung bietet wörtlichen:

select * 
from table 
where theDate >= dateadd(dd, -23, getdate()) 

Aber, wenn ich das Datum ganze Zahl mit einem variablen integer ersetzen die Leistung wieder behindert wird.

Wie kann ich eine Variable hinzufügen und die Leistung beibehalten?

EDIT

tatsächliche Abfrage nach Anforderung enthalten:

DECLARE @days INT 

Set @days = 7 

select c.DEBT_KEY 
     , c.new_value 
     , c.CHANGE_DATE 
from changes c with (nolock) 
where c.C_CODE = 3 
and c.old_value = 4 
and c.CHANGE_DATE >= dateadd(dd, [email protected], getdate()) 

Nein verbindet.

Abfragepläne

Mit Variable (xml explain plan):

enter image description here

Mit Stringliteral (xml explain plan):

enter image description here

So kann ich der Unterschied zu sehen ist tha t Die Variable ruft einen Clustered-Index-Scan (gruppiert) auf, während das String-Literal ein Key-Lookup (Clustered) aufruft ... Ich werde auf Google verweisen müssen, weil ich nicht wirklich etwas über die Performance-Pro/Contra-Werte weiß.

EDIT EDIT

Das funktionierte (xml explain plan):

DECLARE @days INT 

Set @days = 7 

select c.DEBT_KEY 
     , c.new_value 
     , c.CHANGE_DATE 
from changes c with (nolock) 
where c.CHANGE_CODE = 3 
and c.old_value = 4 
and c.CHANGE_DATE >= dateadd(dd, [email protected], getdate()) 
OPTION(OPTIMIZE FOR (@days = 7)) 

enter image description here

... Ich weiß nicht, warum. Außerdem mag ich die Lösung nicht, da sie meinen Zweck der Verwendung einer Variablen negiert, die darin besteht, alle Variablen an die Spitze des Procs zu setzen, um die Notwendigkeit zu reduzieren, im Code während der unvermeidlichen Wartung herumzustochern.

+1

über 1 Milliarde Zeilen und kein Index - wow! Diese Menge nach einem Literal zu suchen, sollte auch ziemlich lange dauern ... Ich würde annehmen, dass es irgendwelche gecachten Ergebnisse gab ... Hast du die Ausführungspläne verglichen? * Ich möchte nicht mit der Indexierung beginnen, ohne sicher zu sein, dass es hilft * Nun kann ich Ihnen versichern, dass ein Index helfen wird :-) – Shnugo

+0

Nun, es gibt einen Index, aber nicht auf 'theDate', ich könnte es gewesen sein Klarer dazu: P –

+1

Bei so vielen Zeilen sollten Sie Indizes für alle Spalten verwenden, die Sie bei Sortier-, Filter- oder Join-Operationen verwenden möchten ... Ein Index ist - einfach gesprochen - eine sortierte Liste der Werte dieser Spalte. Um einen bestimmten Wert in dieser Liste zu finden, ist ein extrem schneller Prozess (teile die Hälfte, schau, ob größer oder kleiner, ah, es ist größer! Teile die obere Hälfte und so weiter ...) Sobald gefunden, sitzen alle Werte zusammen Block. Stellen Sie sich nun einen unsortierten Haufen vor. Ihre Abfrage muss die gesamte Tabelle Zeile für Zeile durchsuchen. – Shnugo

Antwort

0

Die schnelle Version führt eine Clusterschlüssel-Suche durch (kann direkt zu dem Teil der Tabelle gehen, in dem dieser Wert gefunden wird).

Die langsame Version führt einen nicht gruppierten Suchvorgang durch und führt diesen dann mit einem Clustered-Index-Scan zusammen (es muss die gesamte Tabelle durchsucht werden).

Ich sehe die @thisDate Variable ist definiert als Date Typ. Ist möglich, dass die Spalte als DateTime definiert ist? Wenn dies der Fall wäre, würde jeder Wert in @thisDate nicht exakt mit Ihrem Clustered-Index übereinstimmen, was bedeutet, dass die Datenbank die gesamte Tabelle überprüfen muss, wie wir hier sehen. Das Literal hingegen wird als DateTime-Wert interpretiert, der entspricht entspricht Ihrem Tabellenspalte Typ und wird mit dem Index arbeiten.

Wenn dies richtig ist, können Sie die Dinge mit einem sehr einfachen Wechsel fix:

declare @thisDate as datetime 
set @thisDate = '6/5/2016' 

Nur noch 4 Unterschied Zeichen.

Sie können dies auch in Verbindung mit OPTION(RECOMPILE) versuchen, und Sie können auch einen Blick auf OPTIMIZE FOR UNKNOWN werfen.

+0

Dies wurde in den Kommentaren vorgeschlagen, es beschleunigt die Abfrage nicht. ~ 8000 Zeilen wurden in 2 Minuten zurückgegeben. –