En muchas cargas de trabajo de SQL Server, especialmente OLTP, el registro de transacciones de la base de datos puede ser un cuello de botella que aumenta el tiempo que lleva completar una transacción. La mayoría de la gente asume que el subsistema de E/S es el verdadero cuello de botella, ya que no puede mantenerse al día con la cantidad de registro de transacciones que genera la carga de trabajo.
Latencia de escritura del registro de transacciones
La latencia de las operaciones de escritura en el registro de transacciones se puede monitorear usando sys.dm_io_virtual_file_stats
DMV y correlacionado con el WRITELOG
esperas que se están produciendo en el sistema. Grabé un video de demostración del análisis de E/S del registro de transacciones en 2011, por lo que no repetiré todo eso en esta publicación. Puede obtener el video aquí y el código de demostración aquí (adecuado para ejecutar en producción de inmediato).
Si la latencia de escritura es más alta de lo que esperaría para su subsistema de E/S, entonces el subsistema de E/S no puede seguir el ritmo, como es la suposición general. ¿Significa eso que el subsistema de E/S debe mejorarse? No necesariamente.
En muchos sistemas cliente, descubrí que una proporción significativa de los registros que se generan son innecesarios, y si puede reducir la cantidad de registros que se generan, reduce la cantidad de registros de transacciones que se escriben en el disco. Esto debería traducirse en una reducción de la latencia de escritura, reduciendo así el tiempo de finalización de la transacción.
Hay dos causas principales por las que se generan registros extraños:índices no agrupados no utilizados e índices que se fragmentan.
Índices no agrupados no utilizados
Cada vez que se inserta un registro en una tabla, se debe insertar un registro en cada índice no agrupado definido en la tabla (con la excepción de los índices filtrados con los filtros apropiados, que ignoraré a partir de este punto). Esto significa que se generan entradas de registro adicionales, al menos una por índice no agrupado, para cada inserción de tabla. Lo mismo se aplica a la eliminación de un registro en una tabla:los registros coincidentes deben eliminarse de todos los índices no agrupados. Para una actualización de un registro de tabla, los registros de índice no agrupados solo se actualizan si las columnas clave del índice no agrupado o las columnas incluidas formaban parte de la actualización.
Estas operaciones son necesarias, por supuesto, para mantener correcto cada índice no agrupado con respecto a la tabla, pero si la carga de trabajo no utiliza el índice no agrupado, entonces las operaciones y los registros generados por ellos son una sobrecarga innecesaria. Además, si estos índices no utilizados se fragmentan (lo que discutiré más adelante en esta publicación), las tareas regulares de mantenimiento de índices también operarán en ellos, generando aún más registros (desde el índice REBUILD
o REORGANIZE
operaciones) completamente innecesariamente.
Los índices no utilizados provienen de una variedad de fuentes, como alguien que crea por error un índice por columna de la tabla, alguien que crea todos los índices sugeridos por los DMV de índices que faltan o alguien que crea todos los índices sugeridos por el Asesor de ajuste de la base de datos. También podría ser que las características de la carga de trabajo hayan cambiado y, por lo tanto, lo que solían ser índices útiles ya no se usan.
Independientemente de su procedencia, los índices no utilizados deben eliminarse para reducir su sobrecarga. Puede determinar qué índices no se usan usando el DMV sys.dm_db_index_usage_stats, y le recomiendo que lea las publicaciones de mis colegas Kimberly L. Tripp (aquí) y Joe Sack (aquí y aquí), ya que explican cómo usar el DMV correctamente.
Fragmentación de índice
La mayoría de la gente piensa que la fragmentación de índices es un problema que afecta a las consultas que tienen que leer grandes cantidades de datos. Si bien este es uno de los problemas que puede causar la fragmentación, la fragmentación también es un problema debido a cómo ocurre.
La fragmentación es causada por una operación llamada división de página. La causa más simple de una división de página es cuando se debe insertar un registro de índice en una página en particular (debido a su valor clave) y la página no tiene suficiente espacio libre. En este escenario, se llevarán a cabo las siguientes operaciones:
- Se asigna y formatea una nueva página de índice
- Algunos de los registros de la página completa se mueven a la nueva página, creando así espacio libre en la página requerida
- La nueva página está vinculada a la estructura del índice
- El nuevo registro se inserta en la página requerida
Todas estas operaciones generan registros y, como puede imaginar, esto puede ser mucho más de lo necesario para insertar un nuevo registro en una página que no requiere una división de página. En 2009, publiqué en un blog un análisis del costo de división de página en términos del registro de transacciones y encontré algunos casos en los que una división de página generaba más de 40 veces más registros de transacciones que una inserción normal.
El primer paso para reducir el costo adicional es eliminar los índices no utilizados, como describí anteriormente, para que no generen divisiones de página. El segundo paso es identificar los índices restantes que se están fragmentando (y por lo tanto deben estar sufriendo divisiones de página) utilizando sys.dm_db_index_physical_stats
DMV (o el nuevo SQL Sentry Fragmentation Manager) y creando proactivamente espacio libre en ellos usando un factor de relleno de índice. Un factor de relleno le indica a SQL Server que deje un espacio vacío en las páginas de índice cuando el índice se crea, reconstruye o reorganiza, de modo que haya espacio para permitir que se inserten nuevos registros sin necesidad de dividir la página, lo que reduce los registros adicionales generados.
Por supuesto, nada es gratis:la compensación al usar factores de relleno es que está aprovisionando de manera proactiva espacio adicional en los índices para evitar que se generen más registros, pero por lo general es una buena compensación. Elegir un factor de relleno es relativamente fácil y escribí un blog sobre eso aquí.
Resumen
Reducir la latencia de escritura de un archivo de registro de transacciones no siempre significa pasar a un subsistema de E/S más rápido o segregar el archivo en su propia parte del subsistema de E/S. Con un simple análisis de los índices en su base de datos, puede reducir significativamente la cantidad de registros de transacciones que se generan, lo que lleva a una reducción proporcional en la latencia de escritura.
Hay otros problemas más sutiles que pueden afectar el rendimiento del registro de transacciones, y los exploraré en una publicación futura.