Quiero tener una búsqueda rápida basada en si dos columnas son iguales. Intenté usar una columna calculada con un índice, pero SQL Server no parece usarla. Si solo uso una columna de bits rellenada estáticamente con un índice, obtengo la búsqueda de índice esperada.
Parece que hay algunas otras preguntas como esta, pero ninguna se centró en por qué no se usaría un índice.
Tabla de prueba:
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)
Y la consulta:
select Id from Diffs where DiffPersisted = 1
select Id from Diffs where DiffComp = 1
select Id from Diffs where DiffStatic = 1
fuente
COALESCE
en este punto; Creo que laCASE
declaración ya estaba garantizada para regresar0
o1
, peroISNULL
estaba presente solo para que SQL Server produjera un no anulableBIT
para la columna calculada. Sin embargo,COALESCE
seguirá produciendo una columna anulable. Entonces, el único impacto de este cambio, con o sin elCOALESCE
, es que la columna calculada ahora es anulable pero se puede utilizar la búsqueda de índice.COALESCE
? ¿Por qué me lo quedaría?COALESCE
. Traté de mantener el aspecto y la intención de su código original, y no probé sin él, por lo que las pruebas serán suyas. (Tampoco puedo explicar por qué teníasISNULL
allí en primer lugar.)Esta es una limitación específica de la lógica de coincidencia de columnas calculada de SQL Server, cuando
ISNULL
se utiliza un elemento externo , y el tipo de datos de la columna esbit
.Informe de error
Para evitar el problema, se puede emplear cualquiera de las siguientes soluciones:
ISNULL
(la única forma de hacer una columna calculadaNOT NULL
).bit
tipo de datos como el tipo final de la columna calculada.PERSISTED
y active el indicador de traza 174 .Detalles
El meollo del problema es que sin el indicador de traza 174, todas las referencias de columna calculadas en una consulta (incluso persistentes) siempre se expanden a la definición subyacente muy temprano en la compilación de consultas.
La idea de expansión es que podría permitir simplificaciones y reescrituras que solo pueden funcionar en la definición, no solo en el nombre de la columna. Por ejemplo, puede haber predicados en la consulta que hagan referencia a esa columna calculada que podrían hacer que parte del cálculo sea redundante o de otra manera más restringida.
Una vez que se consideran las primeras simplificaciones y reescrituras, la compilación de consultas intenta hacer coincidir las expresiones en la consulta con las columnas calculadas (todas las columnas calculadas, no solo las que se encontraron originalmente en el texto de la consulta).
Las expresiones de columna calculada sin cambios coinciden con la columna calculada original sin problemas en la mayoría de los casos. Parece haber un error cuando es específico para hacer coincidir una expresión de
bit
tipo, con una más externaISNULL
. La coincidencia no tiene éxito en este caso específico, incluso cuando un examen detallado de las partes internas muestra que debería tener éxito.fuente