Actualización de una tabla con millones de registros, han pasado 4 días


12

Actualmente estoy actualizando una tabla con millones de registros, han pasado 4 días y la consulta aún se está ejecutando.

Verifiqué que el monitor de actividad muestra que la consulta se está ejecutando.

En el registro de eventos no hay errores en absoluto.

En cuanto al rendimiento:

  • Tempdb en el disco A (850 gb de espacio libre)
  • archivo de base de datos en el disco B (750 gb de espacio libre)
  • 16 GB de RAM

Por favor sugiérame ¿qué debo hacer?

La consulta

UPDATE
    dbo.table1
SET 
    costPercentage = ISNULL(t2.PaymentIndex, 1.0),
    t2.TopUp_Amt = (ISNULL(t2.PaymentIndex, 1.0) - 1.0)
    * ISNULL(dbo.table1.Initial_Tariff_Amt, 0.00),
    Total_Tariff_Inc_t2 = ISNULL(t2.PaymentIndex, 1.0)
    * ISNULL(dbo.table1.Initial_Tariff_Amt, 0.00)
FROM
    dbo.table2 t2
WHERE
    LEFT(dbo.test1.procodet, 3) = LEFT(t2.ProviderCode, 3) COLLATE database_default 

Respuestas:


3

Hay un detalle interesante en esta consulta que no vi al principio. Gracias a la respuesta de Fabricio Araujo, ahora lo veo: está accediendo a dos tablas. Nunca antes había visto este tipo de uso de la declaración de actualización y no recomiendo usarlo. Le recomiendo que use la sintaxis de unión más intuitiva según la respuesta de Fabricio.

La causa probable es que la unión entre las dos tablas produce un número extremo de filas. Esto podría suceder si la LEFT(col, 3)expresión produce valores duplicados. Si produce 10 duplicados, esto dará como resultado 100000x100000 = 10000000000 filas en el resultado de la unión.

No creo que la indexación juegue un papel aquí. SQL Server puede resolver esta combinación no indexada muy bien con un hash o una combinación de combinación. No toma 4 días.

La otra causa probablemente sería una subestimación de la cardinalidad de las entradas o salidas de unión. SQL Server podría haber elegido una unión en bucle.

Como esto todavía es especulación, le recomiendo que publique el plan de consulta que arrojará luz sobre este problema.


8

Esta consulta requiere que escanee cada fila de la tabla porque

  • Supongo que procodet o ProviderCode no están indexados
  • Incluso si fueron indexados, tiene una IZQUIERDA que es una función en un predicado WHERE
  • Y también tiene COLLATE, que es efectivamente una función en un predicado WHERE

"una función en un predicado WHERE" significa que no se utilizarán índices

Si lo agrupa (digamos en ACTUALIZAR ARRIBA (10000) ... Y costPercentage IS NULL), entonces necesita un índice en costPercentage y esto supone que lo está configurando.

Las únicas soluciones que veo son

  • llenar una nueva tabla en lotes, basándose, por ejemplo, en la clave primaria
  • cree columnas calculadas indexadas para ocultar las expresiones IZQUIERDA y COLLAR, luego ejecute la actualización

@ gbn ... gracias, esa es una gran idea ... pero como los datos están en millones, este proceso llevará tiempo ... Estaba pensando que puede haber una manera de averiguar el progreso de la consulta.
Lucky

1
¿Por qué tomaría 4 días escanear "millones" de filas? No importa cuán grandes e indexadas puedan ser las filas, eso no debería tomar 4 días. La raíz del problema aún se desconoce.
usr

1
Si habitualmente maneja datos de gran tamaño, ¿qué pasa si obtiene un servidor adecuado para eso? Ponga los datos en un SSD, etc.
TomTom

1
@ Suerte seguro. Me dirigía a la respuesta. Hay algo mal que aún no hemos encontrado. No es la consulta en sí misma o el hardware. Eso nunca equivaldría a 4 días de duración.
usr

3
Dado que la consulta está uniendo una porción de 3 caracteres de una columna a una porción de 3 caracteres de otra columna, lo más probable es que el resultado contenga duplicados. Esto es mucho peor que simplemente actualizar millones de filas. Apuesto a que está escaneando a través de una mesa de trabajo en miles de millones.
datagod

4

En primer lugar, cambie la consulta a:

UPDATE t1
SET 
    costPercentage = ISNULL(t2.PaymentIndex, 1.0),
    t2.TopUp_Amt = (ISNULL(t2.PaymentIndex, 1.0) - 1.0)
    * ISNULL(dbo.table1.Initial_Tariff_Amt, 0.00),
    Total_Tariff_Inc_t2 = ISNULL(t2.PaymentIndex, 1.0)
    * ISNULL(dbo.table1.Initial_Tariff_Amt, 0.00)
FROM
  dbo.table1 t1
  inner join dbo.table2 t2
    on LEFT(t1.procodet, 3) = LEFT(t2.ProviderCode, 3) COLLATE database_default 

Según lo indicado por la primera publicación de Jeff Moden en esa discusión , su consulta es muy similar a la que advirtió sobre el "efecto Halloween".

Después de eso, esas expresiones IZQUIERDA deben indexarse. La respuesta de gbn te da consejos sobre cómo hacerlo.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.