Je veux avoir une recherche rapide basée sur si deux colonnes sont égales. J'ai essayé d'utiliser une colonne calculée avec un index, mais SQL Server ne semble pas l'utiliser. Si j'utilise simplement une colonne de bits à remplissage statique avec un index, j'obtiens la recherche d'index attendue.
Il semble qu'il y ait d'autres questions comme celle-ci, mais aucune ne se concentre sur la raison pour laquelle un index ne serait pas utilisé.
Table de test:
CREATE TABLE dbo.Diffs
(
Id int NOT NULL IDENTITY (1, 1),
DataA int NULL,
DataB int NULL,
DiffPersisted AS isnull(convert(bit, case when [DataA] is null and [DataB] is not null then 1 when [DataA] <> [DataB] then 1 else 0 end), 0) PERSISTED ,
DiffComp AS isnull(convert(bit, case when [DataA] is null and [DataB] is not null then 1 when [DataA] <> [DataB] then 1 else 0 end), 0),
DiffStatic bit not null,
Primary Key (Id)
)
create index ix_DiffPersisted on Diffs (DiffPersisted)
create index ix_DiffComp on Diffs (DiffComp)
create index ix_DiffStatic on Diffs (DiffStatic)
Et la requête:
select Id from Diffs where DiffPersisted = 1
select Id from Diffs where DiffComp = 1
select Id from Diffs where DiffStatic = 1
la source
COALESCE
ce point à ce stade; Je crois que laCASE
déclaration était déjà garantie de retourner0
ou1
, maisISNULL
n'était présente que pour que SQL Server produise une valeur non nulleBIT
pour la colonne calculée. Cependant,COALESCE
produira toujours une colonne nullable. Ainsi, le seul impact de ce changement, avec ou sans leCOALESCE
, est que la colonne calculée est désormais nullable mais la recherche d'index peut être utilisée.COALESCE
? Pourquoi devrais-je le garder?COALESCE
. J'ai essayé de conserver l'apparence et l'intention de votre code d'origine, et je n'ai pas testé sans, afin que les tests soient sur vous. (Je ne peux pas non plus expliquer pourquoi vousISNULL
y étiez en premier lieu.)Il s'agit d'une limitation spécifique de la logique de correspondance de colonne calculée SQL Server, lorsqu'un élément le plus à l'extérieur
ISNULL
est utilisé et que le type de données de la colonne l'estbit
.Rapport d'erreur
Pour éviter le problème, l'une des solutions de contournement suivantes peut être utilisée:
ISNULL
(le seul moyen de créer une colonne calculéeNOT NULL
).bit
type de données comme type final de la colonne calculée.PERSISTED
et activez l'indicateur de trace 174 .Détails
Le cœur du problème est que sans l'indicateur de trace 174, toutes les références de colonne calculées dans une requête (même persistées) sont toujours développées dans la définition sous-jacente très tôt dans la compilation de la requête.
L'idée de l'expansion est qu'elle pourrait permettre des simplifications et des réécritures qui ne peuvent fonctionner que sur la définition, pas uniquement sur le nom de la colonne. Par exemple, il peut y avoir des prédicats dans la requête référençant cette colonne calculée qui pourraient rendre une partie du calcul redondante, ou autrement plus contrainte.
Une fois les premières simplifications et réécritures prises en compte, la compilation des requêtes tente de faire correspondre les expressions de la requête aux colonnes calculées (toutes les colonnes calculées, pas seulement celles trouvées à l'origine dans le texte de la requête).
Les expressions de colonne calculées non modifiées correspondent à la colonne calculée d'origine sans problème dans la plupart des cas. Il semble y avoir un bogue lorsqu'il est spécifique à la correspondance d'une expression de
bit
type, avec un élément le plus à l'extérieurISNULL
. L'appariement échoue dans ce cas spécifique, même lorsqu'un examen détaillé des éléments internes montre qu'il doit réussir.la source