2009-10-29 11 views
19

Tengo una tabla de SQL Server en producción que tiene millones de filas, y resulta que necesito agregarle una columna. O, para ser más preciso, necesito agregar un campo a la entidad que representa la tabla.Cómo agrego una columna a la tabla del servidor sql grande

Sintácticamente esto no es un problema, y ​​si la tabla no tuviera tantas filas y no estuviera en producción, sería fácil.

Realmente lo que busco es el curso de acción. Hay muchos sitios web con tablas extremadamente grandes, y deben agregar campos de vez en cuando. ¿Cómo lo hacen sin un tiempo de inactividad sustancial?

Una cosa que debería agregar, no quería que la columna permitiera nulos, lo que significaría que tendría que tener un valor predeterminado.

Entonces, o bien necesito descubrir cómo agregar una columna con un valor predeterminado de manera oportuna, o tengo que encontrar una manera de actualizar la columna en un momento posterior y luego configurar la columna para no permitir nulos .

Respuesta

23
ALTER TABLE table1 ADD 
    newcolumn int NULL 
GO 

no deben tomar tanto tiempo ... Lo que lleva mucho tiempo es insertar columnas en el medio de otras columnas ... b/c, entonces el motor necesita para crear una nueva tabla y copiar los datos en la nueva mesa

+6

sabes qué, tienes razón. Siempre que la columna tenga un valor de NULL, se agrega bastante rápido. Pero si obtengo un valor predeterminado, tomará mucho tiempo. Entonces, el problema real que necesito planear es cómo agregar un valor predeterminado a la columna. –

+10

Agregue la columna y luego realice lotes de ACTUALIZACIÓN relativamente pequeños para rellenar la columna con un valor predeterminado. Eso debería evitar cualquier desaceleración notable. –

+0

Gracias Agent_9191, parece un enfoque bastante decente. –

11

La única solución real para el tiempo de actividad continuo es redundancia.

Acepto la respuesta de @ Nestor de que agregar una nueva columna no debería llevar mucho tiempo en SQL Server, pero aún así, podría ser una interrupción que no es aceptable en un sistema de producción. Una alternativa es hacer el cambio en un sistema paralelo, y luego una vez que la operación se complete, cambie lo nuevo por el anterior.

Por ejemplo, si necesita agregar una columna, puede crear una copia de la tabla, luego agregar la columna a esa copia y luego usar sp_rename() para mover la tabla anterior a un lado y la nueva tabla en su lugar.

Si tiene restricciones de integridad referencial que apuntan a esta tabla, esto puede hacer que el intercambio sea aún más complicado. Probablemente tenga que soltar las restricciones brevemente al intercambiar las tablas.

Para algunos tipos de actualizaciones complejas, puede duplicar por completo la base de datos en un host de servidor separado. Una vez que esté listo, solo intercambie las entradas de DNS para los dos servidores y voilà!

me apoyaron una empresa bursátil en la década de 1990 que corrieron tres servidores de bases de datos duplicadas en todo momento. Esa forma podrían implementar actualizaciones en un servidor, mientras conserva un servidor de producción y un servidor de conmutación por error . Sus operaciones tenían un procedimiento estándar de rotación de las tres máquinas a través de producción, conmutación por error y las funciones de mantenimiento cada día. Cuando necesitaban actualizar el hardware , el software o alterar el esquema de la base de datos , demoraron tres días en propagar el cambio a través de sus servidores , pero podían hacerlo sin interrupción en el servicio. Todas las gracias a la redundancia.

+2

¿Cómo se pone al día en las transacciones perdidas durante el mantenimiento? ¿Replicación estándar? –

+0

Una bolsa de valores no necesita operar 24/7. Se cierran en la campana. –

+0

Doh :-) ¿Pensamientos sobre cómo manejar eso para sistemas 24/7? –

7

"Añadir la columna y luego realizar lotes relativamente pequeños UPDATE para rellenar la columna con un valor por defecto. Eso debería evitar cualquier desaceleraciones notables"

Y después de que usted tiene que fijar la columna a NOT NULL que se disparará en una gran transacción. Entonces, todo funcionará realmente rápido hasta que lo hagas así que probablemente hayas ganado realmente muy poco. Solo sé esto por experiencia de primera mano.

Es posible que desee cambiar el nombre de la tabla actual de X a Y. Puede hacerlo con este comando sp_RENAME '[OldTableName]', '[NewTableName]'.

Recrear la nueva tabla como X con la nueva columna establecida en NOT NULL y luego insertar por lotes de Y a X e incluir un valor predeterminado en su inserción para la nueva columna o colocar un valor predeterminado en la nueva columna cuando recrear tabla X.

He hecho este tipo de cambio en una tabla con cientos de millones de filas. Todavía tardó más de una hora, pero no reventó nuestro registro de trans. Cuando traté de simplemente cambiar la columna a NOT NULL con todos los datos de la tabla, tardé más de 20 horas en matar el proceso.

¿Ha probado simplemente agregar una columna llenándola con datos y estableciendo la columna en NOT NULL?

Así que al final no creo que haya una bala mágica.

3

seleccione en una nueva tabla y cambie el nombre. Ejemplo, añadir la columna i de una tabla:

select *, 1 as i 
into A_tmp 
from A_tbl 

//Add any indexes here 

exec sp_rename 'A_tbl', 'A_old' 
exec sp_rename 'A_tmp', 'A_tbl' 

debe ser rápido y no tocar su registro de transacciones como la inserción en lotes fuerzas. (Acabo de hacer esto hoy con una tabla de 70 millones de filas en < 2 min).

Puede envolverlo en una transacción si necesita que sea una operación en línea (algo puede cambiar en la tabla entre seleccionar y renombrar).

+1

Estoy luchando por entender esto. Usted inserta en 'A_tmp' de' A_tbl'. Pero luego cambia el nombre de 'A_tbl' a' A_old' y luego cambia el nombre de 'A_old' a' A_tbl'. ¿No debería el último cambio de nombre ser de 'A_tmp' a' A_tbl'? – Junto

+0

@Junto sí, lo arreglé –

0

Otra técnica es agregar la columna a una nueva tabla relacionada (Asumir una relación de uno a uno que se puede aplicar dando al FK un índice único). A continuación, puede completar esto en lotes y luego puede agregar la unión a esta tabla donde quiera que aparezcan los datos. Tenga en cuenta que solo consideraría esto para una columna que no quisiera utilizar en cada consulta en la tabla original o si el ancho de registro de la tabla original era demasiado grande o si estaba agregando varias columnas.

6

No quería que la columna permitiera valores nulos, lo que significaría que tendría que tener un valor predeterminado.

Adición de una columna NOT NULL con una restricción DEFAULT a una mesa de cualquier número de filas (incluso mil millones) se convirtió en una partida mucho más fácil en SQL Server 2012 (pero sólo para Enterprise Edition), ya que permitió que fuera una operación en línea (en la mayoría de los casos) donde, para las filas existentes, el valor se leerá de los metadatos y no se almacenará realmente en la fila hasta que se actualice la fila o se reconstruya el índice agrupado.En lugar de parafrasear más, aquí es la sección correspondiente de la página de MSDN para ALTER TABLE:

Añadir columnas NOT NULL como una operación en línea

partir de SQL Server 2012 Enterprise Edition, la adición de un NO NULO columna con un valor por defecto es una operación en línea cuando el valor por defecto es una constante de tiempo de ejecución . Esto significa que la operación se completa casi instantáneamente independientemente del número de filas en la tabla. Esto se debe a que las filas existentes en la tabla no se actualizan durante la operación; en su lugar, el valor predeterminado se almacena solo en los metadatos de la tabla y el valor se busca según sea necesario en las consultas que acceden a estas filas. Este comportamiento es automático; no se requiere sintaxis adicional para implementar la operación en línea más allá de la sintaxis ADD COLUMN. Una constante de tiempo de ejecución es una expresión que produce el mismo valor en tiempo de ejecución para cada fila en la tabla, independientemente de su determinismo. Por ejemplo, la expresión constante "Mis datos temporales", o la función del sistema GETUTCDATETIME() son constantes de tiempo de ejecución. Por el contrario, las funciones NEWID() o NEWSEQUENTIALID() no son constantes de tiempo de ejecución porque se produce un valor único para cada fila de la tabla. Agregar una columna NOT NULL con un valor predeterminado que no sea una constante de tiempo de ejecución siempre se realiza fuera de línea y se adquiere un bloqueo exclusivo (SCH-M) durante la operación.

Mientras que las filas existentes hacen referencia al valor almacenado en los metadatos, el valor predeterminado se almacena en la fila de las nuevas filas que se insertan y no se especifique otro valor para la columna. El valor predeterminado almacenado en metadatos se mueve a una fila existente cuando se actualiza la fila (incluso si la columna real no se especifica en la instrucción UPDATE), o si la tabla o índice agrupado se reconstruye.

las columnas de tipo varchar (max), nvarchar (max), varbinary (max), xml, text, ntext, imagen, hierarchyid, geometría, geografía, o CLR UDTS, no se pueden añadir en una operación en línea. No se puede agregar una columna en línea si al hacerlo, el tamaño de fila máximo posible supera el límite de 8.060 bytes. La columna se agrega como una operación fuera de línea en este caso.

+0

¿Qué pasa con una columna nula SQL Server 2012 edición estándar 14M filas, concurrencia alta 24x7? ¿Será un tiempo de inactividad notable debido al bloqueo del esquema? – Horaciux

+1

@Horaciux ¿Una columna 'NULL' en lugar de' NOT NULL'? Si lo estoy entendiendo correctamente, eso no es un problema. Es solo metadatos y es bastante instantáneo. Antes de que SQL Server 2012 salga con la posibilidad de agregar una columna 'NULL' al instante, siempre que tenga un valor predeterminado, la única forma de agregar una columna sin bloquear nada era agregarlo como' NULL'. Pero luego tenía que rellenarlo a través del trabajo del Agente SQL o hacer conjuntos de 3000 filas por cada ACTUALIZACIÓN (para evitar la escalada del bloqueo). Entonces no, no necesitas preocuparte por una columna 'NULL', al menos no en mi experiencia. –

Cuestiones relacionadas