ACTUALIZAR con JOIN en registros de 100 mm, ¿cómo hacerlo mejor? (en T-SQL)

11

Necesito actualizar 100 millones de registros en una sola tabla, en efecto, normalizando la tabla reemplazando el valor varchar de una columna con simplemente una ID. (Digo "reemplazar" pero realmente estoy escribiendo el ID en otra columna).

Lo que intento lograr es normalizar el conjunto de datos. Los datos aún no normalizados no tienen indexación. Pensé que no crearía índices en los valores sin procesar, esperando, en lugar de indexar las claves foráneas que reemplazarán los valores varchar con los valores tinyint después de que se complete la actualización.

UPDATE A
SET A.AutoClassID = B.AutoClassID
FROM AutoDataImportStaging.dbo.Automobile as A
JOIN AutoData.dbo.AutoClass as B on (A.AutoClassName = B.AutoClassName)

Antecedentes

  • utilizando MSSQL 2008 R2 en Server 2008 R2
  • el servidor tiene 8 GB de RAM
  • el servidor tiene un RAID10, 7200 RPM SATA (no es bueno, lo sé, en producción esto solo leerá datos y no escribirá datos; además, la escasez de HD reciente lo hizo necesario por el costo)
  • el servidor tiene doble CPU Xeon de cuatro núcleos
  • la máquina no está haciendo nada más (actualmente dedicada al desarrollo, solo este proceso)
  • inicio de sesión simple activado (? - pero ¿sigue registrando para poder retroceder?)
  • tenga en cuenta que la consulta hace referencia a dos bases de datos diferentes, para lo que vale
  • El "ancho" de un registro en la tabla que se actualiza es de 455 bytes

Recursos durante la ejecución

  • la RAM física está al máximo
  • la E / S del disco está al máximo
  • La CPU apenas está haciendo nada (el punto de estrangulamiento es E / S)
  • El tiempo de ejecución ha sido de 14 horas y contando!

Sospecho que necesito un índice en los datos sin procesar, aunque descartaré la columna (AutoClassName) después de las actualizaciones de normalización. También me pregunto si debería recorrer la tabla un registro a la vez en lugar de JOIN, lo que parecía ridículo en el momento en que comencé esto, pero ahora parece que hubiera sido más rápido.

¿Cómo debo cambiar mi metodología para mis actualizaciones de normalización restantes (similares a esta) más rápidamente?

Chris Adragna
fuente

Respuestas:

7

Estás intentando hacer esto como una transacción única (muy grande). En su lugar, realice la actualización en lotes más pequeños.

También te beneficiarías de:

  • Un índice temporal en AutoData.dbo.AutoClass.AutoClassName
  • Más RAM Mucho más RAM.
Mark Storey-Smith
fuente
1
+1 Estoy de acuerdo con la actualización por lotes usando la TOPcláusula Ese sería mi enfoque.
Thomas Stringer
Si hago UPDATE TOP, ¿necesitaré una cláusula WHERE (WHERE AutoClassID es NULL)? ¿La cláusula WHERE no introduciría un nuevo impacto en el rendimiento (una exploración de tabla que no estoy haciendo ahora)? Sin duda, disminuiría el problema de RAM que tengo con JOIN.
Chris Adragna
Mi respuesta está muy atrasada, pero en mi caso, SET ROWCOUNT demostró ser el más efectivo.
Chris Adragna
10

Tomaría un enfoque diferente.

En lugar de actualizar las tablas existentes, simplemente cree una nueva tabla que tenga lo que necesita.

Esto seguramente será más rápido:

SELECT DISTINCT
    AutoClassID,
    <Other fields>
INTO
    AutoDataImportStaging.dbo.Automobile
FROM
    AutoData.dbo.AutoClass

Como está escrito actualmente, están ocurriendo muchas operaciones lógicas:

  • Leer todos los valores de A.AutoClassName
  • Leer todos los valores de B.AutoClassName
  • Compare los valores A y B
  • Del conjunto coincidente, lea todos los valores de B.AutoClassID
  • Actualice los valores existentes de A.AutoClassId para que sean el valor de B.AutoClassId a través de los índices que existan
JNK
fuente
Esto suena como un enfoque agradable y simple, especialmente dado el problema de E / S de disco que estoy teniendo. Gracias por responder tan rápido.
Chris Adragna
1
Le sugiero que verifique que tenga suficiente espacio libre en sus archivos de registro y datos. Si los archivos crecen automáticamente, el rendimiento se hundirá. A menudo veo personas que ejecutan una gran actualización única y hacen crecer automáticamente su archivo de registro sin darse cuenta.
Darin estrecho
5

Recorrer la mesa una fila a la vez, ¡no será más rápido!

Como se sospecha y confirma por usted, esto estará vinculado a la E / S: tener un disco, las lecturas, la escritura, los registros de transacciones y (cualquier) espacio de trabajo temporal competirán por la misma E / S.

La recuperación simple seguirá registrando las transacciones, pero el registro será borrado por un punto de control. Es posible que el tamaño del registro inicial y la configuración de crecimiento automático estén causando una ralentización de E / S; el registro de transacciones deberá crecer para acomodar los cambios.

¿Has intentado indexar el campo AutoClassName? ¿Cuántos valores diferentes de AutoClass hay?

Es posible que deba agrupar las actualizaciones, según las limitaciones de su E / S. Así que actualiza 1 millón, punto de control, repite ...

Kev Riley
fuente
Solo hay 15 valores diferentes de AutoClass. Sus comentarios confirman muchas de mis sospechas (¡y dolores!). Gracias por responder.
Chris Adragna
3

Crear índices para los campos de unión.

Siempre puede soltar los índices cuando haya terminado.

Me sorprendería mucho si los índices no mejoraran significativamente el rendimiento de la actualización.

Jimbo
fuente
Estoy seguro de que los índices mejorarían. Supongo que la pregunta es si mejoran más que el tiempo que lleva crear el índice (para un solo uso). Probablemente si. :)
Chris Adragna
3

Exporte de la forma que desee, cree una nueva tabla e importe de nuevo. Como bonificación, tendría una copia de los datos como respaldo, en caso de que ocurrieran milagros.

srini.venigalla
fuente