2010-04-23 29 views
5

Necesito actualizar aproximadamente 250k filas en una tabla y cada campo para actualizar tendrá un valor diferente dependiendo de la fila misma (no calculada en base a la identificación de la fila o la clave pero externamente) .Manera más rápida de actualizar 250k filas con SQL

Intenté con una consulta parametrizada pero resulta lenta (todavía puedo probar con un parámetro de valor de tabla, SqlDbType.Structured, en SQL Server 2008, pero me gustaría tener una forma general de hacerlo en varias bases de datos que incluyen MySql, Oracle y Firebird).

Haciendo un enorme concat de cambios individuales es también lento (pero aproximadamente 2 veces más rápido que hacer miles de llamadas individuales (ida y vuelta!) Utilizar consultas parametrizadas)

¿Qué pasa con la creación de una tabla temporal y ejecutar una actualización unirse a mi mesa y el tmp uno? ¿Funcionará más rápido?

+0

pueden dar un ejemplo del algoritmo que utiliza para determinar cómo los datos con el cambio? ¿Tablas de búsqueda? – Glennular

+0

Los datos que se modificarán provienen del exterior del DB, no hay forma de actualizar usando otras tablas – pablo

+0

"¿Qué tal crear una tabla temporal y ejecutar una actualización que une mi tabla y la de tmp? ¿Funcionará más rápido?" <- Creo que esta es la mejor manera en que puedes lograr el rendimiento. si están en una base de datos diferente, primero intente crear una tabla de etapas y luego actualice la combinación desde esa tabla – Hao

Respuesta

7

¿Qué tan lento es "lento"?

El principal problema con esto es que crearía un enorme entrada en el archivo de registro de la base de datos (en caso de que haya un corte de energía a medio camino a través de la actualización, la base de datos tiene que registrar cada acción para que se pueda deshacer en caso de falla). Esto es más probable de donde viene la "lentitud", más que cualquier otra cosa (aunque obviamente con una cantidad tan grande de filas, hay otras formas de hacer que la cosa sea ineficaz [por ejemplo, hacer un ida y vuelta DB por actualización sería insoportablemente lento] , Solo digo que una vez que elimines las cosas obvias, todavía encontrarás que es bastante lento).

Hay algunas maneras en que puede hacerlo de manera más eficiente. Uno sería hacer la actualización en fragmentos, 1.000 filas a la vez, por ejemplo. De esta manera, la base de datos escribe muchas entradas de registro pequeñas, en lugar de una muy grande.

Otra forma sería apagar o "bajar" el registro de la base de datos durante la actualización. En SQL Server, por ejemplo, puede configurar el Recovery Model en "simple" o "actualización masiva", lo que aceleraría considerablemente (con la advertencia de que corre más riesgo si hay un corte de energía o algo durante la actualización).

Editar Sólo para ampliar un poco más, probablemente la forma más eficiente de ejecutar efectivamente las consultas en el primer lugar sería hacer un inserto grueso de todas las nuevas filas en una tabla temporal, y luego hacer una sola UPDATE de la tabla existente de eso (o para hacer el UPDATE en trozos de 1,000 como dije antes). La mayor parte de mi respuesta era abordar el problema una vez que se ha implementado es así: usted todavía encontrará que es bastante lento ...

+0

Sí, cuando dice "ida y vuelta de BD por actualización", probablemente se refiera a la consulta "parametrizada", ¿no? – pablo

+0

Sí, me refiero a "ACTUALIZAR bla, SET blah" 250,000 veces. Incluso con consultas parametrizadas, va a ser * muy * lento porque todavía está haciendo una ida y vuelta de red a la base de datos para cada una. –

+0

Sí, haciendo solo una: "Actualizar blah set blah; actualizar blah1 set blah1; ...." es mucho más rápido que usar consultas parametrizadas, pero es más lento (es decir, más lento que insertar la misma cantidad de filas usando un BulkCopy en SQL Server) – pablo

2

Si las columnas actualizados son parte de índices que podrían

  • caída de estos índices
  • hacer la actualización
  • volver a crear los índices.

Si necesita estos índices para recuperar los datos, bueno, no ayuda.

+0

Sí, pero los índices no parecen ser el problema, sino los recorridos de ida y vuelta. – pablo

+0

Dejar caer y recrear índices también ayudará, sí. Pero si está haciendo ACTUALIZACIONES individuales, entonces el rendimiento de actualizar los índices cada vez probablemente esté siendo "ahogado" por los viajes de ida y vuelta de la red, etc. –

+1

Entonces tienes tu respuesta. La única forma de deshacerse del viaje de ida y vuelta es hacer el cálculo en el lado del servidor. Coloque la lógica en un procedimiento almacenado y realice una única actualización. –

3

llamada a un procedimiento almacenado si es posible

1

Se debe utilizar la SqlBulkCopy con el indicador KeepIdentities.

Como parte de un SqlTransaction haga una consulta para SELECCIONAR todos los registros que necesitan actualización y luego ELIMINARLOS, devolviendo los registros seleccionados (y ahora eliminados). Léelos en C# en un solo lote. Actualice los registros en el lado de C# en la memoria, ahora que ha reducido la selección y luego SqlBulkCopie esos registros actualizados atrás, claves y todo. Y no te olvides de comprometer la transacción. Es más trabajo, pero es muy rápido.

0

Esto es lo que yo haría:

  1. Recuperar toda la tabla, es decir, las columnas que necesita con el fin de calcular/recuperar/buscar/producir los cambios externamente
  2. Calcular/producir esos cambios
  3. Ejecute una inserción masiva en una tabla temporal, cargando la información que necesita en el servidor para realizar los cambios. Esto requeriría la información clave + nuevos valores para todas las filas que pretenda cambiar.
  4. Ejecute SQL en el servidor para copiar nuevos valores de la tabla temporal en la tabla de producción.

Pros:

  • que ejecuta el servidor del lado del último paso es más rápido que ejecutar toneladas y toneladas de SQL individuales, por lo que vamos a bloquear la tabla en cuestión durante un tiempo más corto
  • inserción masiva de este tipo es rápido

Contras:

  • requiere espacio adicional en su base de datos para la tabla temporal
  • produce más datos de registro, registrando tanto la inserción masiva y los cambios en la tabla de producción
0

Éstos son cosas que pueden hacer que sus actualizaciones lenta:

  • actualizaciones ejecución de uno en uno a través de la consulta parametrizada
    • solución: actualización en una declaración
  • gran transacción crea gran entrada de registro
  • actualización de índices (RDBMS actualizará índice después de cada fila.Si cambia la columna indexada, que podría ser muy costosa en la gran mesa)
    • si se puede, la caída de los índices antes de la actualización y volver a ellos después de
  • campo de actualización que tiene restricción de clave externa - para cada registro insertado RDBMS ir a buscar tecla adecuada
    • si se puede, desactivar restricciones de clave externa antes de la actualización y les permitirá después de la actualización
  • disparadores y fila las pruebas de nivel
    • si se puede, desactivar los disparadores antes de la actualización y les permitan después
Cuestiones relacionadas