2010-11-30 12 views

Respuesta

8

Casualmente, tuve que hacer algo muy similar hace 3 horas. La mesa era 35m filas, es bastante amplia, y se tarda mucho en simplemente hacer esto:

alter table myTable add myNewColumn int not null default 0; 

Esto es lo que lo terminé yendo con:

alter table myTable add myNewColumn int null; 

while 1=1 
begin 
    update top (100000) myTable 
    set 
     myNewColumn = 0 
    where 
     myNewColumn is null; 

    if @@ROWCOUNT = 0 break; 
end 

alter table myTable alter column myNewColumn int not null; 
alter table myTable add constraint tw_def_myNewColumn default (0) for myNewColumn; 

En esta ocasión, el alter table las declaraciones fueron casi instantáneas. Pasaron entre 7 y 8 minutos (en un servidor lento) para realizar los lotes de actualización. Estoy especulando que SQL Server estaba generando deshacer en mi consulta original para restaurar los valores, pero no esperaba que comenzara.

De todos modos, en su caso, tal vez algo similar podría ayudar. Podría intentar agregar una nueva columna de bigint, actualizar la nueva columna en lotes y luego establecer las restricciones en ella.

+0

No encontré ninguna diferencia en el rendimiento entre el cambio del tamaño de la columna y el copiado en una nueva columna en una tabla con más de 10 millones de filas. –

+0

¿Qué significa que fue lento en ambos casos? – Matt

2

cree la nueva tabla que desee, con los tipos de columnas y los índices correctos. (script fuera de la tabla anterior, y cambie el nombre.)

inserte en la nueva tabla (lista de columnas) seleccione * de tabla_antigua;

cambie el nombre de la antigua tabla de la antigua tabla, cambie el nombre de la tabla nueva tabla_nuevo.

crear los índices antiguos en la nueva tabla, soltar cualquier restricción ri en la tabla anterior y crearlos en la nueva tabla. Una vez más, sus rdbms tendrán una manera fácil de generar scripts para hacer esto.

+0

es la selección en una nueva tabla en una columna con un diferente tipo de datos más rápido que cambiar el tipo de datos de una columna existente? Estamos haciendo esto para las columnas de Clave principal. –

+0

Generalmente mucho más rápido; en lugar de tener que cambiar el tamaño de cada fila, solo crea nuevas filas del tamaño correcto. – tpdi

0

Acabo de toparme con esto hace unas semanas con una tabla con 639m filas. Terminé creando una nueva tabla y copiando los datos en "lotes". Tomó aproximadamente 2 días en el servidor principal y la replicación tardó 3 días en replicarlo todo. Luego modifiqué todas las vistas y procesos que usaban en la tabla anterior. Esto me permitió solucionar algunos problemas, como deshacerme de una columna que no quería y seleccionar (en algunos casos) mejores índices. Después de que todos los datos se movieron sql cambiados, entonces solté la tabla anterior.

Un desastre, pero ahora soy más sabio. Use grandes entradas para identificar claves primarias si el sistema será de larga vida y existe la posibilidad de que haya millones de filas.

1

Acabo de encontrarme con este problema ... Una tabla con 447,732,310 registros en ella. Si un compañero de trabajo presentara una solución excelente, solo le tomará unos 24 minutos copiar los datos a una nueva tabla, aproximadamente 40 minutos para crear índices.

Aquí es lo que hicimos:

--Get ntiles of idOrders, split up into 100 groups - 1:20 minutes 
IF(OBJECT_ID('TEMPDB..#x')) IS NOT NULL 
    DROP TABLE #x 

SELECT nt, MIN(idOrder) idOrderMin, MAX(idOrder) idOrderMax 
INTO #X 
FROM (
     SELECT idOrder, NTILE(100) OVER(ORDER BY idOrder) nt 
     FROM (
       SELECT DISTINCT idOrder FROM order_raw_fields 
     ) X 
) Y 
GROUP BY nt 

-- view results 
--SELECT * FROM #x ORDER BY idOrderMin 

-- create new table 
SELECT TOP 0 * 
INTO ORDER_RAW_FIELDS_Intl 
FROM ORDER_RAW_FIELDS 

ALTER TABLE dbo.ORDER_RAW_FIELDS_Intl 
    ALTER COLUMN value nvarchar(500) 

--Build queries 
SELECT 'insert into ORDER_RAW_FIELDS_Intl select * from order_raw_fields 
where idOrder >= ' + CAST(idOrderMIn AS VARCHAR(100)) + ' and idOrder <= ' + CAST(idOrderMax AS varchar) InsertStmt 
    INTO #inserts 
FROM #X 
ORDER BY idOrderMin 

DECLARE insertCursor CURSOR LOCAL FAST_FORWARD FOR 
    SELECT InsertStmt 
    FROM #inserts 

OPEN insertCursor 

-- 24:04 minute execution time to match 
DECLARE @insertStmt NVARCHAR(125) 
FETCH NEXT FROM insertCursor INTO @insertStmt 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    --EXECUTE @insertStmt 
    EXECUTE sp_executesql @[email protected] 

    PRINT 'Execution Complete: ' + @insertStmt 

    FETCH NEXT FROM insertCursor INTO @insertStmt 
END 

CLOSE insertCursor 
DEALLOCATE insertCursor 

-- Add indexes 
-- 21:37 minutes completion time 
ALTER TABLE [dbo].[ORDER_RAW_FIELDS_Intl] ADD CONSTRAINT [PK_ORDER_RAW_FIELDS_Intl] PRIMARY KEY CLUSTERED 
(
    [idRow] ASC, 
    [idOrder] ASC, 
    [remoteFieldName] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 92) ON [PRIMARY] 
GO 

-- 13:45 minutes completion time 
CREATE NONCLUSTERED INDEX [IX_idOrder_remoteFieldName2] ON [dbo].[ORDER_RAW_FIELDS_Intl] 
(
    [idOrder] ASC, 
    [remoteFieldName] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 94) ON [PRIMARY] 
GO 

-- drop table 
TRUNCATE TABLE [dbo].[ORDER_RAW_FIELDS] 
DROP TABLE [dbo].[ORDER_RAW_FIELDS] 

-- renamed new table to old tables's name 
EXEC sp_rename 'ORDER_RAW_FIELDS_Intl', 'ORDER_RAW_FIELDS'; 
Cuestiones relacionadas