SQL Server: ¿Cubriendo índices que incluyen todas las columnas?

9

Nuestro equipo ha heredado una aplicación y una base de datos asociada. Los desarrolladores anteriores parecen haber aplicado una regla en la que cada índice, en cada tabla, tiene una cláusula INCLUDE para agregar siempre cada columna que de otro modo no es parte de la clave. Estas tablas tienen en promedio entre dos y cinco índices o restricciones únicas, así como claves foráneas.

La intención parece ser mejorar el rendimiento de SELECT independientemente de qué consulta se arroje a la base de datos, ya que el acceso es a través de un ORM que, de manera predeterminada (pero no siempre) recupera todas las columnas. Esperamos que los efectos secundarios de esto sean mayores requisitos de almacenamiento (posiblemente significativamente) y un tiempo adicional para INSERT / UPDATE / DELETE.

La pregunta es, ¿es esta una estrategia sensata? Nuestro equipo tiene antecedentes con SQL Server pero no hay miembros que se consideren expertos en su comportamiento interno (aunque se ha planteado la cuestión de que si esta estrategia fuera óptima, ¿no sería la predeterminada ahora?). ¿Qué otros efectos secundarios (uso de CPU / memoria / TempDB del servidor de base de datos, etc.) deberíamos esperar, o algunos de nuestros supuestos anteriores son incorrectos?

Además, la aplicación se puede instalar tanto en SQL Server local (versiones desde 2012) como en Azure SQL, en caso de que estemos preparados para cualquier diferencia entre los dos, o efectos secundarios adicionales en Azure, como resultado de esto ¿Acercarse?

T2PS
fuente

Respuestas:

8

He hecho esto en índices específicos antes de ahora, para ayudar a realizar consultas pesadas a menudo. Efectivamente, lo que han hecho es crear múltiples índices agrupados: cuando cualquiera de esos índices se utiliza para buscar filas, no se necesita trabajo adicional para buscar el resto de los datos en el índice agrupado real (o el montón si no hay un índice agrupado real) .

¿Es esta una estrategia sensata?

Para algunos índices donde sea necesario para admitir ciertos patrones de consulta, ciertamente sí.

Pero para hacer esto con todos los índices, diría que no.

Va a ser un desperdicio de espacio para hacer donde no se necesita realmente, y ralentizará las inserciones / actualizaciones de manera significativa. Puede ralentizar tantas consultas de lectura como sea útil, ya que cada página de índice contiene menos registros, por lo que cualquier consulta que necesite hacer referencia a un fragmento del índice para filtrar pero no usar todas las demás columnas tendrá que acceder a más páginas. Esto hará que su base de datos tenga más memoria: esas páginas deberán cargarse en el grupo de búferes, expulsando potencialmente otras páginas útiles si la memoria es baja. Si se utiliza la compresión en esos índices para intentar mitigar el efecto sobre el almacenamiento y los requisitos de memoria, en su lugar, se cargará una carga adicional a las CPU.

ya que el acceso es a través de un ORM que por defecto (pero no siempre) recupera todas las columnas

Este es un patrón común con un uso poco optimizado de un ORM (o simplemente ORM ingenuos) y en estos casos he visto que el asesor de índices de SQL Server (y herramientas similares de terceros) sugieren índices con muchas INCLUDEcolumnas d, por lo que estaría de acuerdo con su sugerencia de que es por eso que los índices se han creado de esta manera.

Pero aunque puede hacer que todas esas consultas sean un poco más rápidas y algunas de ellas significativamente más rápidas, sospecho que en muchos casos cualquier beneficio es tan pequeño que no valdrá la huella de memoria adicional requerida por su conjunto de trabajo común, el espacio en el disco y El IO entre el disco y la memoria.

También recuerde que el ORM podría no estar seleccionando todas las columnas de todas las tablas que toca una consulta, por lo que el beneficio solo puede mantenerse para el objetivo principal de la solicitud actual, y los índices más grandes pueden penalizar la consulta cuando se usan otros objetos para filtrar pero no devuelve datos ( SELECT * FROM table1 WHERE id IN (SELECT someID FROM table2 WHERE someColumn='DesiredValue')tal vez).

Otra consideración para el exceso de espacio utilizado, particularmente si los datos son grandes, es que tendrá un impacto en su estrategia de respaldo: costos de almacenamiento y transferencia para esos respaldos, tiempos potenciales de restauración, etc.

¿deberíamos estar preparados para cualquier diferencia entre los dos [on-prem y AzureSQL]

En general, creo que las consideraciones aquí serán las mismas en cada caso, aunque cualquier exceso de memoria / costo de IO impuesto por los índices grandes puede ser más directamente visible en Azure, donde puede ajustar el nivel de servicio y, por lo tanto, el costo de la infraestructura es más fácil que teniendo un conjunto relativamente fijo de recursos de hardware. Si usa niveles estándar / premium en lugar de precios basados ​​en vcore, se verá más afectado por el costo de IO en estándar, ya que premium incluye significativamente más IO por DTU. Si usa copias de seguridad de varias regiones o redundancia u otras características no locales en Azure, puede haber un costo de ancho de banda asociado con el espacio adicional que ocupan los índices innecesariamente anchos.

David Spillett
fuente
Seguimos adelante e hicimos esta eliminación. Un efecto secundario fue que en ciertas tablas, SELECTsin especificar, ORDER BYcomenzó a devolver las mismas filas que antes pero con un orden arbitrario diferente.
T2PS
Eso no es inesperado. El orden de los resultados sin 'ORDER BY' es, por definición, indefinido y puede cambiar cada vez que el planificador de consultas decida adoptar un enfoque diferente, lo que puede hacer como resultado de cambios en el índice o cambios en sus patrones de datos a medida que crece. Otros factores pueden hacer tal cambio de orden en una fecha posterior, incluso sin este cambio. Si confía en el orden de salida de una declaración, incluso superficialmente, entonces debe incluir un 'ORDER BY' para garantizarlo.
David Spillett
Oh definitivamente. El comentario anterior fue más como una nota de recordatorio para cualquiera que encuentre esta respuesta más tarde.
T2PS
5

La pregunta es, ¿es esta una estrategia sensata? ... (aunque se ha planteado la cuestión de que si esta estrategia fuera óptima, ¿no sería la predeterminada ahora?)

En la mayoría de los casos, esta no es una estrategia sensata. La razón es que, en general, en las bases de datos OLTP, las filas devueltas al usuario final no serán muchas. (Generalización)

La pregunta que debe hacerse es, si está buscando en las columnas clave, ¿cuántas filas devolverá esa operación de búsqueda? Y repita eso para las consultas que buscan en esa columna.

Considere la siguiente tabla, que devuelve muchas columnas, where SelectiveIDField= ...

select columnA,columnC, ... columnZ
FROM dbo.BigTable
Where SelectiveIDField= '225122141';

Si selectiveIDFieldla búsqueda activa solo devuelve una fila , ¿la búsqueda adicional de claves es algo tan malo? (suponiendo que tiene índices agrupados aquí, de lo contrario, búsqueda RID)

Solo hará una búsqueda de clave adicional, una ejecución adicional + el operador de combinación. Incluso si es 10 o incluso 100, ¿sería un impacto tan grande? Esto también depende de cuánto se ejecuta su consulta y qué tan importante es el tiempo de ejecución.

En el caso de que sea insignificante, solo cree el índice SelectiveIDFieldy llámelo un día, no debería valer la pena las ganancias de lectura en comparación con las pérdidas de escritura.

En resumen, en mi opinión, la creación de índices en toda la tabla no debería ser un enfoque predeterminado a menos que realmente vea un problema con una consulta y pueda mejorarlo drásticamente agregando un índice de cobertura completo.

Randi Vertongen
fuente