Pregunta

Tengo una vista indexada simple. Cuando pregunto en contra, es bastante lento. Primero te muestro los esquemas e índices. Entonces las consultas simples. Finalmente una consulta de plan de consulta.

Actualización: Prueba de solución al final de esta publicación.

Esquema

Esto es lo que parece: -

CREATE view [dbo].[PostsCleanSubjectView] with SCHEMABINDING AS
    SELECT PostId, PostTypeId, 
        [dbo].[ToUriCleanText]([Subject]) AS CleanedSubject
    FROM [dbo].[Posts]

Mi udf ToUriCleanText simplemente reemplaza varios caracteres con un carácter vacío. P.ej. reemplaza todos los caracteres '#' con ''.

Luego agregué dos índices sobre esto: -

Índices

Índice de clave principal (es decir, índice agrupado)

CREATE UNIQUE CLUSTERED INDEX [PK_PostCleanSubjectView] ON 
    [dbo].[PostsCleanSubjectView] 
(
    [PostId] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF,
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

Y un índice no agrupado

CREATE NONCLUSTERED INDEX [IX_PostCleanSubjectView_PostTypeId_Subject] ON 
    [dbo].[PostsCleanSubjectView] 
(
    [CleanedSubject] ASC,
    [PostTypeId] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF,
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

Ahora, esto tiene alrededor de 25K filas. Nada grande en absoluto.

Cuando hago las siguientes consultas, ambas toman alrededor de 4 segundos impares. WTF? Esto debería ser ... ¡básicamente instantáneo!

Consulta 1

SELECT a.PostId
FROM PostsCleanSubjectView a 
WHERE a.CleanedSubject = 'Just-out-of-town'

Consulta 2 (se agregó otro elemento de cláusula donde)

SELECT a.PostId
FROM PostsCleanSubjectView a 
WHERE a.CleanedSubject = 'Just-out-of-town' AND a.PostTypeId = 1

¿Qué he hecho mal? ¿El UDF está arruinando las cosas? Pensé que, como he indexado esta vista, se materializaría. Como tal, no tendría que calcular esa columna de cadena.

Aquí hay una captura de pantalla del plan de consulta, si esto ayuda: - alt text

Además, ¿observa el índice que está usando? ¿Por qué utiliza ese índice?

Ese índice es ...

CREATE NONCLUSTERED INDEX [IX_Posts_PostTypeId_Subject] ON [dbo].[Posts] 
(
    [PostTypeId] ASC,
    [Subject] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, 
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

Entonces, sí, ¿alguna gente de ideas?

Actualización 1: esquema agregado para el udf.

CREATE FUNCTION [dbo].[ToUriCleanText]
(
    @Subject NVARCHAR(300)
)
RETURNS NVARCHAR(350) WITH SCHEMABINDING
AS 
BEGIN
   <snip>
   // Nothing insteresting in here. 
   //Just lots of SET @foo = REPLACE(@foo, '

Actualización 2: Solución

Sí, fue porque no estaba usando el índice en la vista y tenía que asegurarme manualmente de no expandir la vista. El servidor es Sql Server 2008 Standard Edition. La respuesta completa está abajo. Aquí está la prueba, WITH (NOEXPAND) alt text

Gracias a todos por ayudarme a resolver este problema :)

, ''), etc. END

Actualización 2: Solución

Sí, fue porque no estaba usando el índice en la vista y tenía que asegurarme manualmente de no expandir la vista. El servidor es Sql Server 2008 Standard Edition. La respuesta completa está abajo. Aquí está la prueba, WITH (NOEXPAND) alt text

Gracias a todos por ayudarme a resolver este problema :)

¿Fue útil?

Solución

¿Qué edición de SQL Server? Creo que solo Enterprise Edition y Developer Edition utilizarán las vistas indizadas automáticamente, mientras que las demás lo admitirán utilizando sugerencias de consulta.

SELECT a.PostId
FROM PostsCleanSubjectView a WITH (NOEXPAND)
WHERE a.CleanedSubject = 'Just-out-of-town' AND a.PostTypeId = 1

De Sugerencias de consulta (Transact SQL) en MSDN :

  

La vista indexada no se expande solo si se hace referencia directa a la vista en la parte SELECT de la consulta y se especifica WITH (NOEXPAND) o WITH (NOEXPAND, INDEX (index_value [, ... n])).

Otros consejos

Veo un signo @ en el código de consulta en su plan de ejecución. Hay una variable de cadena involucrada.

Sql Server tiene un comportamiento NASTY si el tipo de variable de cadena no coincide con el tipo de la columna de cadena en el índice. El servidor Sql ... convertirá toda la columna a ese tipo, realizará la búsqueda rápida y luego desechará el índice convertido para que pueda hacer todo de nuevo la próxima consulta.


Simon lo descubrió, pero aquí hay más detalles útiles: http: // msdn.microsoft.com/en-us/library/ms187373.aspx

  

Si una consulta contiene referencias a columnas que están presentes tanto en una vista indexada como en tablas base, y el optimizador de consultas determina que usar la vista indexada proporciona el mejor método para ejecutar la consulta, el optimizador de consultas utiliza el índice en la vista. . Esta función se denomina coincidencia de vista indizada y solo se admite en las ediciones Enterprise y Developer de SQL Server.

     

Sin embargo, para que el optimizador considere las vistas indexadas para hacer coincidir o use una vista indexada a la que se hace referencia con la sugerencia NOEXPAND, las siguientes opciones de SET deben estar activadas:

Entonces, lo que está sucediendo aquí es que la coincidencia de vista indizada no está funcionando. Asegúrese de que está utilizando las ediciones Enterprise o Developer de Sql Server (muy probablemente). Luego revise las opciones de SET según el artículo.

Recientemente construí una gran base de datos que contiene cientos de millones de registros de detalles de llamadas y hay algunas funciones que estaba usando en consultas y vistas que convertí en columnas computadas persistentes. Esto funcionó mucho mejor porque podía indexar en la columna calculada.

Sin embargo, no estaba usando SQL Enterprise, así que no tuve la oportunidad de usar vistas indizadas. ¿Se supone que la vista indexada puede indexar los resultados deterministas del FDU?

Sospecho que tiene que llamar a esa función para cada fila antes de que pueda hacer la comparación en su cláusula where. Expondría el tema, ejecutaría la comprobación de la consulta directamente y vería cómo funcionan los tiempos. En general, he visto mucha lentitud cada vez que modifico un valor utilizando una función y luego lo uso en la cláusula where ...

¿Qué beneficio está buscando al usar una vista indexada? ¿No es posible indexar correctamente la (s) tabla (s)? Sin una buena justificación, está agregando complejidad y solicitando al optimizador que maneje más objetos de base de datos con menos flexibilidad.

¿Ha evaluado la misma lógica de consulta con índices estándar?

La mezcla en la lógica UDF confunde las cosas aún más.

Si lo único que desea es conservar el valor de retorno de una UDF, considere una columna calculada persistente en lugar de una vista indexada.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top