Reconstruir índice de clave primaria muy grande


13

Tengo una base de datos SQL que está alojada en Azure. El problema es que el tamaño se está descontrolando, puedo ver hasta un 99% de fragmentación en los índices agrupados de la clave primaria.

Puedo reconstruir todos los demás índices con la online=onopción y no afectará el rendimiento. El tamaño de uno de los índices de PK Clustered es superior a 200 GB, y para este REBUILD...WITH (ONLINE=ON)causa un bloqueo.

Tenemos usuarios de todas las zonas horarias que acceden al sitio, así que realmente, no puedo encontrar un momento en el que pueda reconstruir el índice sin conexión.

¿Cuál es la mejor estrategia para reconstruir índices grandes sin tener un tiempo de inactividad en el sitio?

Creo que reorganizar no ayudará, ya que la fragmentación es del 99%. El problema es que la mesa se bloquea incluso en línea. El principal problema es que el índice es superior a 200 GB. La clave primaria es un entero.


44
@Techy, incluso con una alta fragmentación, REORGANIZEreducirá la fragmentación de la página de la hoja y el espacio compacto REBUILD, de manera menos eficiente. ¿Estás seguro de que el gran tamaño se debe a la fragmentación? ¿Cuál es el factor de relleno?
Dan Guzman

¿Sabes qué está causando la fragmentación? ¿Qué tan pronto después de su reconstrucción volverá a la casilla 1? ¿Puedes publicar más información sobre tu mesa?
Pacreely

2
@Techy He editado la pregunta para agregar información adicional basada en tus comentarios. Sería útil si también incluyera la definición de la tabla en la pregunta, y detalles adicionales relacionados con "la tabla se bloquea incluso cuando [se reconstruye] en línea". ¿Qué tipo de esperas estás viendo?
AMtwo

Respuestas:


9

Aunque es un poco tarde, responderé con la esperanza de que ayude o al menos rechace algunas ideas / comentarios adicionales sobre este tema porque creo que es una buena pregunta.

Primero, y no sé si está haciendo esto o no, pero no asuma que los altos niveles de fragmentación en el índice siempre causarán un bajo rendimiento. Las estadísticas obsoletas (por ejemplo, sys.dm_db_stats_properties ) y grandes cantidades de espacio en blanco por página (es decir, la columna avg_page_space_used_in_percent en sys.dm_db_index_physical_stats dmv ) tienen más relevancia con respecto a los problemas de rendimiento que la fragmentación sola. Sí, los índices altamente fragmentados generarán más puntos de lectura y, por lo general, verá estadísticas obsoletas y niveles más altos de espacio en blanco por página junto con la fragmentación, pero la fragmentación no está directamente vinculada a las optimizaciones del plan de consulta ni a la cantidad de memoria que carga el índice desde el disco realmente consumirá Los planes de consulta se ven afectados por las estadísticas y su huella de memoria se hincha con más espacio en blanco . Por ejemplo, un índice que está 99% fragmentado pero tiene menos de 5% de promedio. el espacio en blanco y las estadísticas actualizadas probablemente no le causen problemas drásticos de rendimiento en comparación con un mal plan de ejecución como resultado de estadísticas obsoletas o paginación constante de un índice que es demasiado grande para caber completamente en la memoria porque hay una cantidad significativa de espacio en blanco presente por página.

Si la fragmentación es realmente un problema , puede reducirla, EN LÍNEA, emitiendo una ALTER INDEX ... REORGANIZEdeclaración identificada por Dan Guzman en los comentarios. Esto no creará un índice tan ágil como lo REBUILDhará una operación, pero reducirá su fragmentación. La clave aquí es identificar ventanas de menor uso en su base de datos y ejecutarlas luego. Esto podría ser de 15 minutos o varias horas, obviamente, cuanto más tiempo mejor, pero la clave aquí es que esta operación no retrocede y retiene cualquier progreso realizado incluso si lo matas a mitad de la ejecución.

Si, en un mundo perfecto donde se eliminó su fragmentación, ¿ tendría más sentido utilizar la partición en esta tabla? Azure SQL Database permite la partición de tablas y Microsoft tiene un excelente artículo que describe algunas estrategias de Particionamiento para Azure SQL Database . Si sus datos no son volátiles, particionarlos puede ayudar a reducir las necesidades de mantenimiento, y si se combina con Table Compression , incluso puede reducir su huella de almacenamiento general. La respuesta anterior de Alberto Murillo alude a la utilización de particionamiento horizontal basado en una región de datos, y este enfoque puede ayudar a crear algunas ventanas de mantenimiento para usted, ya que sus datos serían más específicos regionalmente en lugar de global.

La transición a una tabla particionada no será fácil con su ausencia actual de ventanas de mantenimiento, pero es posible que pueda utilizar un enfoque descrito por Maria Zakourdaev que utiliza vistas particionadas sobre la parte superior de su tabla actual y una nueva tabla particionada para iniciar la partición datos futuros A medida que pasa el tiempo (y es de esperar que se eliminen sus datos antiguos), con el tiempo puede pasar completamente a la tabla particionada. Nuevamente, no conozco sus datos o aplicación, pero quizás este enfoque sea algo que pueda emplear.


4

Primero, es importante considerar si la fragmentación es importante.

Si su consulta solo realiza búsquedas de una sola fila, es posible que no note ninguna fragmentación. En las SAN modernas, el almacenamiento en caché a nivel de SAN puede hacer que las E / S físicas sean lo suficientemente rápidas como para que la fragmentación no importe. En SSD, el patrón de E / S aleatorio causado por el escaneo de un índice fragmentado en realidad puede resultar en un mejor rendimiento que los datos no fragmentados.

Muchas veces, las personas notan que reconstruir un índice solucionó un problema de rendimiento. La reconstrucción de un índice también genera estadísticas nuevas. Puede darse el caso de que la solución real sean estadísticas nuevas, no la reconstrucción del índice. UPDATE STATISTICS...WITH FULLSCANpuede ser una forma más barata, más rápida y menos intrusiva de resolver el mismo problema de rendimiento.

Si no tiene problemas causados ​​por la fragmentación, podría estar gastando mucho tiempo y esfuerzo sin obtener ganancias reales.

En segundo lugar, hay dos tipos de fragmentación:

  1. Fragmentación física Esto es lo que piensa la mayoría de la gente cuando piensa en la fragmentación. Las páginas están fuera de servicio y deben reordenarse. Al escanear un índice, este tipo de fragmentación a veces puede ser un problema. En general, he notado que esto tiene el mayor impacto en el rendimiento con lecturas físicas . Si está viendo los resultados sys.dm_db_index_physical_stats, este número es la avg_fragmentation_in_percentcolumna.

  2. Fragmentación de baja densidad. Esta fragmentación es causada por páginas que solo están parcialmente llenas de datos. Tiene baja densidad de datos porque sus datos se distribuyen en más páginas de las necesarias. Como resultado, leer los datos requiere más E / S porque los datos se distribuyen en más páginas de las necesarias. Esto puede afectar tanto las lecturas lógicas como físicas. Si está viendo los resultados sys.dm_db_index_physical_stats, este número es la avg_page_space_used_in_percentcolumna. Esta columna solo se completa cuando se usa el modo SAMPLEDo DETAILED.

Entonces, ¿qué haces al respecto?

Fragmentación física : si simplemente persigue números altos avg_fragmentation_in_percent, considere realmente si está perdiendo el tiempo. Asegúrese de tener una consulta real que tenga un rendimiento deficiente y use un entorno de prueba para confirmar que está solucionando un problema eliminando la fragmentación.

Puede abordar la fragmentación física haciendo ALTER INDEX...REORGANIZE. La REORGANIZEoperación está en línea, moviendo las páginas de una en una para reorganizarlas nuevamente en orden físico. Si elimina una REORGANIZEdeclaración a mitad de camino, cualquier trabajo que ya se haya realizado se mantiene: solo se revertirá la página que se está moviendo actualmente. Hacer una REORGANIZEtabla grande que esté muy fragmentada puede requerir más espacio total de registro de transacciones, y en modo de recuperación completa puede generar una cantidad significativa de copias de seguridad del registro de transacciones. También puede llevar más tiempo para REORGANIZEun índice altamente fragmentado que para REBUILDél.

A menudo verá consejos para realizar un REBUILDíndice altamente fragmentado, en lugar de un REORGANIZE: esto se debe a que la reconstrucción desde cero puede ser más eficiente. Sin embargo, la reorganización puede ser una operación "más en línea" y a veces se prefiere, incluso para índices altamente fragmentados.

La fragmentación de baja densidad no puede ser reparada por REORGANIZE. Solo se puede solucionar haciendo un ALTER INDEX...REBUILD. Al hacer el índice con ONLINE=ON, debería poder minimizar el bloqueo. Sin embargo, REBUILDtodavía necesita tomar un candado por un momento para intercambiar el índice antiguo por el nuevo índice. En un sistema muy ocupado, lograr este bloqueo exclusivo a veces puede ser un problema. Debería poder confirmar si tiene este problema utilizando algo como sp_whoisactive para examinar el bloqueo durante su reconstrucción y mirando los detalles de los bloqueos y esperas. Usar la WAIT_AT_LOW_PRIORITYopción puede ser útil si sabe que hay un próximo período de baja utilización, y su reconstrucción puede "colarse" para este intercambio cuando la actividad cae lo suficiente como para alcanzar ese bloqueo. Tenga en cuenta que un largo plazoREBUILDLa operación también será una transacción abierta de larga duración. Las transacciones abiertas de larga duración pueden tener sus propios problemas, relacionados con el uso / reutilización del registro de transacciones. Si está utilizando duplicación o grupos de disponibilidad, también hay consideraciones para rehacer el registro de transacciones en la réplica secundaria.


La fragmentación de baja densidad (también conocida como "fragmentación interna") a menudo se repara mediante a REORGANIZE. Del BOL : "Reorganizar también compacta las páginas de índice". Bueno, siempre que el FILLFACTOR actual del índice permita la densidad que buscas.
Granger

2

aviso

Después de este comentario:

Perderá las filas que se insertan durante la copia. Si desea evitar esto bloqueando la tabla, entonces terminará con el mismo problema que el OP indicado en su pregunta. También 200Gb no vendrá gratis :-) - Marco Sep 5 '17 a las 11:18

... veo cómo este enfoque no funcionará.

Dejaré esta respuesta como un ejemplo de lo que no se debe hacer.


Si tiene más de 200 GB libres en su Azure DB, puede ser astuto con la "reconstrucción", copiando sus datos en una tabla totalmente nueva y ordenándolos allí.

Tratar:

  • escribiendo su guión LiveTableen un vacíoNewTable
  • copiando el LiveTableen elNewTable
  • renombrar LiveTableaOldTable
  • renombrar NewTableaLiveTable

Obviamente, use el nombre de su tabla en lugar de LiveTable.


Oreo, usaría el mismo enfoque que tú. Incluso cuando hay filas insertadas durante la copia, puede agregarlas después cuando NewTable ha cambiado de nombre a LiveTable. El principal problema que evita aquí es el tiempo de inactividad extendido. Incluso podría bcp (copiar en E / S). No es una mala idea, así que tampoco entiendo el voto negativo :-)
Koen D

1

Idealmente, si un índice está bien diseñado, no deberíamos tener que jugar con el mecanismo de bloqueo.

Me parece que necesitará aceptar el bloqueo para desfragmentar el índice agrupado. Si hay una buena posibilidad de que esto vuelva a suceder, considere rediseñar el índice agrupado (debe ser estrecho, único, estático y en constante aumento).

No estoy seguro de qué versión de SQL Server está utilizando, pero podría intentar lo siguiente en 2012:

  • SET DEADLOCK_PRIORITY LOW - Esto le dice al motor que la reconstrucción del índice debe ser la víctima del punto muerto cuando / si ocurre uno.

  • MaxDOP = 1 - El valor MaxDOP limita el número total de CPU lógicas utilizadas en paralelo para crear el índice (2005 en adelante, solo edición Enterprise).

También puede cambiar la configuración de bloqueos de página / fila, pero no lo haría sin probar. Podría empeorar el bloqueo, especialmente si es un índice mal diseñado.

A partir de 2014, existe la siguiente opción que básicamente le dice al motor que permita que continúen otras sesiones y que la operación de índice en línea espere:

(WAIT_AT_LOW_PRIORITY (MAX_DURATION = 1 MINUTES, ABORT_AFTER_WAIT = SELF))

0

¡He utilizado el mismo enfoque que Oreo descrito anteriormente con gran éxito! Lo único que falta es que necesita ejecutar un script de actualización después de copiar los datos y realizar el último cambio de nombre.

La actualización se verá así:

Insert from OldTable into LiveTable
  Where not exists (select From OldTable Where LiveTable.Key = OldTable.Key)

Si la clave es una columna de identidad, debe utilizar un enfoque ligeramente diferente.


Como se señaló en la respuesta de Oreo, su método no funcionará si todavía se agregan datos a la tabla original, a menos que bloquee la tabla original que anula el propósito del ejercicio
Tom V - intente topanswers.xyz

-2

Intente utilizar el fragmentación para distribuir los datos de su base de datos geográficamente. Entonces podrá identificar diferentes ventanas de mantenimiento para cada ubicación geográfica, y el tiempo para realizar el mantenimiento será más corto. Esto también mejorará el rendimiento. Puedes obtener más información sobre este artículo. No espere a que la base de datos se agrande.

Con grandes bases de datos y usuarios conectados las 24 horas del día, los 7 días de la semana, debe utilizar la reorganización del índice y actualizar solo las estadísticas que deben actualizarse (sp_updatestats) para minimizar el tiempo necesario para el mantenimiento y el impacto para los usuarios.

Espero que esto ayude.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.