¿Cómo puedo agregar una columna de versión de fila a una tabla grande con un tiempo de inactividad mínimo?

21

Sin embargo, con SQL Server 2008 y versiones posteriores, quiero agregar una columna de versión de fila a una tabla grande cuando simplemente

ALTER TABLE [Tablename]
ADD Rowversion [Rowversion] NOT NULL

Entonces la tabla no está disponible para actualizaciones por demasiado tiempo.

¿Qué estrategias puedo usar para reducir este tiempo de inactividad? Consideraré cualquier cosa. Cuanto más simple, mejor, por supuesto, pero consideraré cualquier estrategia.

Mi opinión es que, como último recurso, podría mantener una copia de la tabla de etapas mantenida por los desencadenantes y luego sp_rename la tabla de etapas en la tabla original. Pero espero algo más simple / fácil.

Michael J Swart
fuente

Respuestas:

26

Considere crear una nueva tabla con el mismo esquema más la columna de versión de fila, y agregue una vista encima de ambas tablas que una toda la unión. Haga que las personas usen la vista y escriban en lugar de disparadores contra las tablas y vistas subyacentes.

Las inserciones deben enviarse a la nueva tabla, las actualizaciones deben mover los datos a la nueva tabla y las eliminaciones deben aplicarse a ambas tablas.

Luego, realice movimientos por lotes en segundo plano, moviendo tantos registros a la vez como pueda a la nueva tabla. Todavía puede tener problemas de concurrencia mientras esto sucede, y algunos planes de ejecución craptaculares, pero le permite permanecer en línea mientras ocurren los movimientos.

Lo ideal es que comience el proceso un viernes por la tarde para minimizar el efecto en los usuarios finales e intente hacerlo antes del lunes por la mañana. Una vez que está en su lugar, puede cambiar la vista para apuntar solo a la nueva tabla, y los planes de ejecución craptaculares desaparecen. Idealmente.

Para evitar que los disparadores se activen cuando los datos se migran en lotes, observe el número de filas en las tablas eliminadas / insertadas en el disparador y omita las actividades si están cerca del número de filas en su lote.


Al final, Michael decidió omitir la vista (y no eliminarla de la tabla original) para obtener planes más estables. La compensación contenía esencialmente dos copias de la tabla. Lo convirtió en una serie de publicaciones de blog .

Brent Ozar
fuente
7

Si tiene tiempo para planificar con anticipación, hay una solución mucho más fácil ... (generalmente)

Los largos bloqueos son casi seguramente causados ​​por divisiones de página en la capa de almacenamiento. Así que forzarlos en su propio horario.

  1. Agregue una columna temporal con capacidad NULL con tipo de datos VARBINARY(8).
  2. Encuentre el tiempo de inactividad disponible en la base de datos para actualizar lotes de los registros existentes con un valor válido para el campo. ( 0x0000000027F95A5Bpor ejemplo)
  3. Las actualizaciones forzarán las divisiones de página necesarias y asignarán más espacio a la tabla.
  4. Cuando esté atrapado, suelte la columna temporal (no toca el almacenamiento asignado) y agregue la columna de versión de fila.
  5. No hay divisiones de página, y un bloqueo que solo se necesita el tiempo suficiente para completar los valores.

Lo he usado con éxito para agregar una columna de versión de fila a una tabla de filas de 150M en menos de 10 minutos.

Advertencia ... si tiene una tabla con grandes campos varchar (especialmente varchar(max)), SQL Server decide reconstruir la tabla en lugar de reutilizar el nuevo espacio disponible. Todavía estoy tratando de encontrar una forma de evitarlo.

Scott Lynch
fuente
Interesante, supongo que no especifiqué qué significaba "demasiado tiempo" en mi pregunta. Si> 30 minutos es demasiado tiempo para su escenario y 10 minutos son tolerables, esta solución funcionaría. Mi escenario implicaba tratar de lograr un tiempo de inactividad cero o más específicamente <10 segundos, lo que se logra con la respuesta de Brent.
Michael J Swart
1

Si lo TIMESTAMPque está agregando es NULLABLE:

  1. Agregar una VARBINARY(8)columna
  2. Rellenar con datos.

Después de rellenar, en las instrucciones SQL consecutivas, DROPla VARBINARY(8)columna que acaba de agregar y rellenar, y agregue la TIMESTAMP NULLcolumna.


Si lo TIMESTAMPque está agregando es NOT NULLABLE:

  1. Agregar una BINARY(8)columna
  2. Rellenar con datos.

Después de que se haya completado, en las instrucciones SQL consecutivas, DROPla BINARY(8)columna que acaba de agregar y que se completó y la ADD THE TIMESTAMP NOT NULLcolumna.

Paul White dice GoFundMonica
fuente