Agregar columnas a las tablas de producción

28

¿Cuál es la mejor manera de agregar columnas a tablas de producción grandes en SQL Server 2008 R2? Según los libros en línea de Microsoft:

Los cambios especificados en ALTER TABLE se implementan de inmediato. Si los cambios requieren modificaciones de las filas de la tabla, ALTER TABLE actualiza las filas. ALTER TABLE adquiere un bloqueo de modificación de esquema en la tabla para asegurarse de que ninguna otra conexión haga referencia incluso a los metadatos de la tabla durante el cambio, excepto las operaciones de índice en línea que requieren un bloqueo SCH-M muy corto al final.

(http://msdn.microsoft.com/en-us/library/ms190273.aspx)

En una mesa grande con millones de filas, esto puede llevar un tiempo. ¿Es la interrupción la única opción? ¿Cuál es la mejor manera de manejar este tipo de situación?

sh-beta
fuente
1
Artículo reciente sobre este problema: sqlservercentral.com/articles/Change+Tracking/74397
8kb

Respuestas:

27

"Depende"

Si agrega una columna que no requiere agregar datos a las filas, entonces puede ser bastante rápido.

Por ejemplo, agregar un int o char requiere movimientos físicos de fila. Agregar un varchar anulable sin valor predeterminado no debería (a menos que el mapa de bits NULL necesite expandirse)

Debe probarlo en una copia restaurada de la producción para obtener una estimación.

La creación de una nueva tabla, la copia y el cambio de nombre pueden llevar más tiempo si tiene que volver a agregar índices y claves en una tabla de mil millones de filas.

He cambiado miles de millones de tablas de filas que tomaron unos segundos para agregar una columna anulable.

¿Dije que primero hiciera una copia de seguridad?

gbn
fuente
2
+1 en la copia de seguridad. y asegúrese de tener suficiente espacio de registro también.
SqlACID
¿Puedes aclarar por qué agregar un int o char requiere movimientos físicos de fila?
sh-beta
55
¿Quiso decir "no" requiere agregar datos a las filas en su segunda línea?
Ben Brocka
21

Si la columna es NULLable, el impacto debe ser insignificante. Si la columna no puede ser NULL y el valor debe establecerse, entonces puede ser bastante diferente. Lo que haría en este caso es, en lugar de agregar una restricción no nula y predeterminada en una sola toma, agregando efectivamente datos a cada fila:

  • agregue la columna como NULLable: debe ser rápida en la mayoría de los casos
  • actualizar los valores por defecto
    • puedes hacer esto en lotes si es necesario
    • También puede usar esto para aplicar lógica condicional donde algunas filas pueden no obtener el valor predeterminado
  • agregue las restricciones no nulas / predeterminadas
    • esto será más rápido cuando ninguno de los datos sea NULO, pero aún así debe ser medible

De acuerdo con @gbn en que puede probar esto restaurando una copia de producción y probándola allí ... obtendrá una buena idea del tiempo (suponiendo que el hardware sea algo similar) y también puede ver el impacto en el registro de transacciones.

Aaron Bertrand
fuente
Re el último bit: •add the not null/default constraintsno estoy seguro de que no haya un problema potencial con esto ... Cuando MSSQL (incluso 2008R2) cambia una columna no nula a nula, si pones un rastro puedes verlo realmente debajo de las cubiertas haciendo una actualización completa de cada fila de la tabla, es decir update table1 set column1 = column1, supongo que está haciendo la verificación no nula de una manera completamente idiota. Esta transacción es el doble del tamaño de la tabla (páginas anteriores y posteriores), por lo que para una tabla DW puede ser enorme. Anteriormente hemos tenido que bcp datos, truncar, hacer cambios nulos a no nulos, luego bcp.
Si alguien sabe una forma de evitar esto, me encanta saber ... En contraste, en Oracle, cambiar nulo a no nulo hace un bloqueo, luego una selección para verificar que no haya nulos y luego una actualización instantánea de metadatos.
Hola @ Mike, esto suena como una buena pregunta potencial por derecho propio.
Derek Downey
4

Ha considerado:

  1. Crear una nueva tabla que incluya los cambios en la definición de la tabla.
  2. Inserción en la nueva definición de tabla seleccionando desde la tabla original.
  3. Cambiar el nombre de la tabla original a _orig y luego renombrar la nueva tabla al nombre de la tabla original.

La desventaja aquí es que debe tener suficiente espacio en la base de datos para realizar este cambio. Es posible que aún necesite un bloqueo de lectura en la tabla para evitar lecturas sucias.

Sin embargo, minimiza el impacto para los usuarios finales si existe la posibilidad o la necesidad de acceder simultáneamente a la tabla original. También debe minimizar la duración de la cerradura.

RobPaller
fuente
¿No necesitarías un bloqueo de escritura , en lugar de leer? Está bien que los usuarios vean datos en la tabla anterior, simplemente no desea que confirmen ningún cambio que se sobrescribirá cuando finalice el intercambio de búfer.
Jon of All Trades
Ese fue mi pensamiento con mi sombrero de almacén de datos sobre dónde los cambios se pueden controlar un poco más fácil. En una situación OLTP está en lo correcto, sería necesario un bloqueo de escritura para evitar que se realicen cambios en la tabla.
RobPaller