2010-09-13 22 views
7

Tenemos una serie de bases de datos que almacenan de 10 a 100 gigabytes de datos en una de las tablas. Contiene datos de imagen. El problema es que muchas de estas bases de datos se crearon de forma incorrecta. Básicamente, la clave principal no es en realidad una clave principal. Se crearon con un índice único en una columna que admite nulos. Y algunos de ellos tienen un int como clave principal en lugar de un bigint.Manera eficiente de alterar la tabla de 100 GB

Estamos revisando y arreglando estas bases de datos. Se ejecutan en SQL Server 2000 a través de SQL Server 2008, aunque la mayoría de los que tienen problemas de clave primaria están en SQL Server 2000. El problema es que no queremos bloquear la base de datos durante todo un día mientras se convierte la tabla. Hemos analizado varias estrategias:

  1. Indique a SQL Server que cambie directamente el tipo de columna. Esto bloquea la tabla hasta que esté completa, y después de dejarla durante la noche en muchos casos, aún no se terminó.

  2. Inserte todas las imágenes en una nueva tabla de una vez. Esto se interrumpió más fácilmente, pero la tabla completa básicamente se escribe en el archivo de registro en el proceso.

  3. Insertar 100 filas a la vez, donde no existen las filas de la tabla de destino. Lo bueno es que pueden seguir usando la base de datos mientras esto sucede (con un gran impacto en el rendimiento) y que puede detenerse y reiniciarse arbitrariamente en cualquier punto, y evita los archivos de registro de 100 GB +. Esto es lo que estamos haciendo actualmente, pero encontrar las 100 mejores filas que no existen se vuelve muy lento a medida que la tabla objetivo se hace cada vez más grande. UPDATE STATISTICS y DBCC INDEXDEFRAG ayudan considerablemente, pero en el intento más reciente, llegamos al punto de que incluso 100 imágenes a la vez estaban sentadas allí sin responder.

    INSERT INTO %s 
        SELECT TOP 100 Source.* 
        FROM %s AS Source WITH (NOLOCK) 
        LEFT OUTER JOIN %s AS Target WITH (NOLOCK) ON Source.DocumentID = Target.DocumentID 
        WHERE Target.DocumentID IS NULL 
        ORDER BY Source.DocumentID 
    

Así que la pregunta es, ¿hay una opción que puede copiar los datos a granel de una manera eficiente y resumable? No tiene que ser 100% exacto, siempre podemos regresar y corregir cualquier discrepancia al final, siempre que haga el 99% del trabajo.

Respuesta

3

The join is the problem. No hagas eso. Simplemente recorra su tabla actual utilizando un intervalo razonable, usando el actual índice agrupado. Algo así como:

Declare @idrange int; 
Set @idrange = 1; 

WHILE @idrange < 10000000 

INSERT INTO Destination 
    SELECT * 
    FROM Source 
    WHERE DocumentID between @idrange and @idrange + 999 
    ORDER BY Source.DocumentID 

Set @idrange = @idrange + 1000 
End 

Tenga en cuenta que la mejor velocidad, eliminar todos los índices (incluyendo el índice agrupado) de la tabla de destino, a continuación, añadir los índices han sido insertados vez que todas las filas.

EDITAR: cambió el intervalo de rango para evitar una superposición (ya que entre incluye los puntos finales)

Una última aclaración: el punto general de mi escritura de la muestra es que simplemente quiere caminar a través de los registros actuales en un orden razonable, y ponerlos todos en la nueva tabla en lotes. No hay ninguna razón para continuar revisando la tabla de destino cada vez, ya que ya debe saber lo que ha puesto ahí y lo que queda. La mayoría de las veces, tiene sentido utilizar el índice agrupado (si lo hay), ya que esto significa que puede recorrer el orden físico de la tabla sin realizar búsquedas en los marcadores. Si la tabla no tiene clúster, simplemente usa lo que sea más lógico (tu PK, probablemente).

+0

La clave principal en esta tabla no está agrupada. La conversión a un índice agrupado sería casi tan doloroso como recrear la tabla, porque tiene que reorganizar físicamente todos los datos. –

+0

Hacerlo por rangos es definitivamente más eficiente que el método de unión. Tendré que ver cómo funciona en la práctica, pero lo que esperaba era que hubiera alguna manera de ejecutar las inserciones de una manera no atómica, donde si se detiene a medio camino, dejaría lo que ya está hecho, y evitar la escritura extra en el archivo de registro. –

+0

@Bryce Wagner: si no está agrupado en PK, realice un rango o agrupación equivalente en lo que * esté * en clúster. (Por favor dígame si tiene un clúster, y que no es solo un HEAP) – BradC

Cuestiones relacionadas