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 1Ihnen hinzugefügte hat integerstandardmäßig den Datentyp . Beim Hinzufügen eines integerWerts zu einem numeric(18,0)Wert wendet SQL Server die Regeln mit der Priorität des Datentyps an . inthat 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 @lowerdann 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 BIGINTMöglichkeit auf zu ändern . BIGINTerfordert 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.