Beginnend mit Ihrer ursprünglichen Abfrage:
declare
@lower numeric(18,0) = 1000,
@upper numeric(18,0) = 1005;
select * from [messages]
where msg_id between @lower+1 and @upper;
Das von 1
Ihnen hinzugefügte hat integer
standardmäßig den Datentyp . Beim Hinzufügen eines integer
Werts zu einem numeric(18,0)
Wert wendet SQL Server die Regeln mit der Priorität des Datentyps an . int
hat eine niedrigere Priorität, so dass es in a konvertiert wird numeric(1,0)
. Ihre Anfrage entspricht der folgenden:
declare
@lower numeric(18,0) = 1000,
@upper numeric(18,0) = 1005;
select * from [messages]
where msg_id between @lower+CAST(1 AS NUMERIC(1, 0)) and @upper;
Ein anderer Satz von Regeln für Präzision, Skalierung und Länge wird angewendet, um den Datentyp des beteiligten Ausdrucks zu bestimmen @lower
. Es ist nicht sicher, nur zu verwenden, NUMERIC(18,0)
da dies überlaufen könnte (betrachten Sie 999.999.999.999.999.999 und 1 als Beispiel). Die hier geltende Regel lautet:
╔═══════════╦═════════════════════════════════════╦════════════════╗
║ Operation ║ Result precision ║ Result scale * ║
╠═══════════╬═════════════════════════════════════╬════════════════╣
║ e1 + e2 ║ max(s1, s2) + max(p1-s1, p2-s2) + 1 ║ max(s1, s2) ║
╚═══════════╩═════════════════════════════════════╩════════════════╝
Für Ihren Ausdruck lautet die resultierende Genauigkeit:
max(0, 0) + max(18 - 0, 1 - 0) + 1 = 0 + 18 + 1 = 19
und die resultierende Skala ist 0. Sie können dies überprüfen, indem Sie den folgenden Code in SQL Server ausführen:
declare
@lower numeric(18,0) = 1000,
@upper numeric(18,0) = 1005;
SELECT
SQL_VARIANT_PROPERTY(@lower+1, 'BaseType') lower_exp_BaseType
, SQL_VARIANT_PROPERTY(@lower+1, 'Precision') lower_exp_Precision
, SQL_VARIANT_PROPERTY(@lower+1, 'Scale') lower_exp_Scale;
Dies bedeutet, dass Ihre ursprüngliche Abfrage der folgenden entspricht:
declare
@lower numeric(19,0) = 1000 + 1,
@upper numeric(18,0) = 1005;
select * from [messages]
where msg_id between @lower and @upper;
SQL Server kann nur @lower
dann eine Clustered-Index-Suche durchführen, wenn der Wert implizit in konvertiert werden kann NUMERIC(18, 0)
. Es ist nicht sicher, einen NUMERIC(19,0)
Wert in zu konvertieren NUMERIC(18,0)
. Infolgedessen wird der Wert als Prädikat anstatt als Suchprädikat angewendet. Eine Problemumgehung besteht darin, Folgendes zu tun:
declare
@lower numeric(18,0) = 1000,
@upper numeric(18,0) = 1005;
select * from [messages]
where msg_id between TRY_CAST(@lower+1 AS NUMERIC(18,0)) and @upper;
Diese Abfrage kann beide Filter als Suchprädikate verarbeiten:
Mein Rat ist, den Datentyp in der Tabelle nach BIGINT
Möglichkeit auf zu ändern . BIGINT
erfordert ein Byte weniger als NUMERIC(18,0)
und profitiert von nicht verfügbaren Leistungsoptimierungen, um eine NUMERIC(18,0)
bessere Unterstützung für Bitmap-Filter zu ermöglichen.