En una pregunta anterior mía, ¿es una buena idea deshabilitar la escalada de bloqueo al agregar nuevas columnas calculadas a una tabla? , Estoy creando una columna calculada:
ALTER TABLE dbo.tblBGiftVoucherItem
ADD isUsGift AS CAST
(
ISNULL(
CASE WHEN sintMarketID = 2
AND strType = 'CARD'
AND strTier1 LIKE 'GG%'
THEN 1
ELSE 0
END
, 0)
AS BIT
) PERSISTED;
La columna calculada es PERSISTED
, y de acuerdo con computed_column_definition (Transact-SQL) :
Persistió
Especifica que el Motor de base de datos almacenará físicamente los valores calculados en la tabla y actualizará los valores cuando se actualicen cualesquiera otras columnas de las que depende la columna calculada. Marcar una columna calculada como PERSISTED permite crear un índice en una columna calculada que es determinista, pero no precisa. Para obtener más información, vea Índices en columnas calculadas. Cualquier columna calculada utilizada como columna de partición de una tabla particionada debe marcarse explícitamente como PERSISTED. computed_column_expression debe ser determinista cuando se especifica PERSISTED.
Pero cuando intento crear un índice en mi columna me sale el siguiente error:
CREATE INDEX FIX_tblBGiftVoucherItem_incl
ON dbo.tblBGiftVoucherItem (strItemNo)
INCLUDE (strTier3)
WHERE isUsGift = 1;
El índice filtrado 'FIX_tblBGiftVoucherItem_incl' no se puede crear en la tabla 'dbo.tblBGiftVoucherItem' porque la columna 'isUsGift' en la expresión del filtro es una columna calculada. Vuelva a escribir la expresión del filtro para que no incluya esta columna.
¿Cómo puedo crear un índice filtrado en una columna calculada?
o
¿Hay una solución alternativa?
fuente
WHERE (sintMarketID = 2 AND strType = 'CARD' AND strTier1 LIKE 'GG%')
.Respuestas:
Desafortunadamente, a partir de SQL Server 2014, no existe la posibilidad de crear un lugar
Filtered Index
donde el filtro está en una columna calculada (independientemente de si es persistente o no).Ha habido un elemento de conexión abierto desde 2009, así que adelante y vote por él. Quizás Microsoft arregle esto algún día.
Aaron Bertrand tiene un artículo que cubre varios otros problemas con los índices filtrados .
fuente
Aunque no puede crear un índice filtrado en una columna persistente, existe una solución bastante simple que puede usar.
Como prueba, he creado una tabla simple con una
IDENTITY
columna y una columna calculada persistente basada en la columna de identidad:Luego, creé una vista vinculada al esquema basada en la tabla con un filtro en la columna calculada:
A continuación, creé un índice agrupado en la vista vinculada al esquema, que tiene el efecto de persistir los valores almacenados en la vista, incluido el valor de la columna calculada:
Inserte algunos datos de prueba en la tabla:
Cree un elemento de estadísticas y un índice en la vista:
Realizar
SELECT
declaraciones en la tabla con la columna persistente ahora puede usar automáticamente la vista persistente, si el optimizador de consultas determina que tiene sentido hacerlo:El plan de ejecución real para la consulta anterior muestra que el optimizador de consultas eligió usar la vista persistente para devolver los resultados:
Es posible que haya notado la conversión explícita en la
WHERE
cláusula anterior. Este explícitoCONVERT(INT, 26)
permite que el optimizador de consultas use correctamente el objeto de estadísticas para estimar el número de filas que devolverá la consulta. Si escribimos la consulta conWHERE pv.TestComputedColumn = 26
, el optimizador de consultas puede no estimar adecuadamente el número de filas ya que 26 se considera realmente aTINY INT
; esto puede hacer que SQL Server no use la vista persistente. Las conversiones implícitas pueden ser muy dolorosas, y vale la pena usar constantemente los tipos de datos correctos para comparaciones y uniones.Por supuesto, todas las "trampas" estándar que resultan del uso del enlace de esquema se aplican al escenario anterior; Esto puede evitar el uso de esta solución en todos los escenarios. Por ejemplo, ya no será posible modificar la tabla base sin eliminar primero el enlace del esquema de la vista. Para hacerlo, deberá eliminar el índice agrupado de la vista.
Si no tiene SQL Server Enterprise Edition, el optimizador de consultas no usará automáticamente la vista persistente para consultas que no hacen referencia directa a la vista usando la
WITH (NOEXPAND)
sugerencia. Para obtener el beneficio de usar la vista persistente en versiones que no sean Enterprise Edition, deberá volver a escribir la consulta anterior en algo como:Gracias a Ian Ringrose por señalar la limitación de Enterprise Edition anterior, y a Paul White por el
(NOEXPAND)
pista.Esta respuesta de Paul tiene algunos detalles interesantes sobre el optimizador de consultas en relación con las vistas persistentes.
fuente
TestComputedColumn
lugar. Sin embargo, dado que el índice agrupado contiene todos los datos para la tabla / vista, decidí que sería mejor usar un número monotónicamente creciente como clave de agrupamiento. Tenga en cuenta que en realidad no probé esa suposición, y de hecho puede ser incorrecta para algunas variaciones de la reproducción.De
Create Index
y suwhere
cláusula, esto no es posible:Fuente: MSDN
fuente
Antes de calcular las columnas, utilizamos disparadores para calcular el valor de las columnas cada vez que se cambiaba o insertaba la fila.
(Un disparador también podría usarse para insertar / eliminar el PK del elemento de una segunda tabla que luego se usó en consultas).
fuente
Este es un intento de mejorar el trabajo de Max Vernon . En su solución, sugiere usar 2 índices en la vista y un objeto de estadísticas.
El primer índice está agrupado, lo que en realidad es necesario ya que, a diferencia de un índice no agrupado en una tabla, se generará un error si se intenta la creación de un índice no agrupado en la vista sin tener primero un índice agrupado.
El segundo índice es un índice no agrupado, que se utiliza como índice detrás de la consulta. En la sección de comentarios de su respuesta, le pregunté qué pasaría si se usara un índice agrupado en lugar de un índice no agrupado.
El siguiente análisis intenta responder a esta pregunta.
Estoy usando exactamente el mismo código, excepto que no estoy creando un índice no agrupado en la vista.
Tampoco estoy creando un objeto de estadísticas. Si sigue y utiliza SQL Server Management Studio (SSMS) para ingresar el código a continuación, debe tener en cuenta que puede ver algunas líneas onduladas rojas, que parecen errores. Estos (probablemente) no son errores, pero involucran un problema con intellisense.
Puede desactivar intellisense o simplemente ignorar los errores y ejecutar los comandos. Deben completarse sin errores.
El siguiente plan de ejecución (sin vista de vista / índice) se produce después de ejecutar la siguiente consulta en la tabla:
Esto proporciona una línea de base para comparar. Observe que después de completar la consulta, se creó un objeto de estadísticas (_WA_Sys_00000003_1FCDBCEB). El objeto de estadísticas PK_PersistedViewTest se creó cuando se creó el índice de tabla en clúster.
A continuación, se crean la vista filtrada y el índice agrupado en esa vista:
Ahora, intentemos ejecutar la consulta nuevamente, pero esta vez en la vista:
El nuevo plan de ejecución es ahora:
Si se cree en el nuevo plan, después de agregar la vista y el índice agrupado en esa vista, las estadísticas parecen indicar que el tiempo requerido para ejecutar la consulta ahora se ha duplicado. Además, observe que no se creó un nuevo objeto de estadísticas para admitir el nuevo índice después de que se ejecutó la consulta, que es diferente de la consulta en la tabla.
El plan de consulta aún sugiere que la creación de un índice no agrupado sería bastante útil para mejorar el rendimiento de la consulta. Entonces, ¿eso significa que se debe agregar un índice no agrupado a la vista antes de que se pueda obtener la mejora de rendimiento deseada? Hay una última cosa para probar. Modifique la consulta para usar la opción "WITH NOEXPAND":
Esto da como resultado el siguiente plan de consulta:
Este plan de ejecución se parece bastante al que se produjo con el índice no agrupado que figura en la respuesta de Max Vernon. Pero, este se hace con un índice menos (no agrupado) y un objeto de estadísticas menos.
Resulta que la opción NOEXPAND debe usarse con las versiones express y estándar de SQL Server para hacer un uso adecuado de una vista indizada. Paul White tiene un excelente artículo que expone los beneficios de usar la opción NOEXPAND. También recomienda que esta opción se use con la edición empresarial para garantizar que el optimizador utilice la garantía de unicidad proporcionada por los índices de vista.
El análisis anterior se realizó con la edición express de SQL Sever 2014. También lo probé con la edición de desarrollador de SQL Server 2016. La opción NOEXPAND no parece ser necesaria con la edición de desarrollo para lograr las mejoras de rendimiento, pero todavía se recomienda .
Hace menos de 5 meses, Microsoft hizo las ediciones para desarrolladores gratuitas . La licencia restringe el uso solo al desarrollo, lo que significa que la base de datos no se puede usar en un entorno de producción. Entonces, si ha estado buscando probar tablas optimizadas de memoria, cifrado, R, etc., entonces ya no tiene la excusa sin licencia. Lo instalé con éxito en mi computadora hace unos días junto con SQL Server 2014 Express sin problemas.
fuente