2010-10-26 24 views
6

En primer lugar, déjenme decir que me estoy ejecutando en SQL Server 2005, por lo que no tengo acceso a MERGE.Borrar todo/Inserción masiva

Tengo una tabla con ~ 150k filas que actualizo a diario desde un archivo de texto. Como las filas caen del archivo de texto, necesito eliminarlas de la base de datos y si cambian o son nuevas, necesito actualizarlas/insertarlas en consecuencia.

Después de algunas pruebas, he encontrado que en cuanto al rendimiento, es exponencialmente más rápido hacer una eliminación completa y luego insertar a granel desde el archivo de texto en lugar de leer el archivo línea por línea haciendo una actualización/inserción. Sin embargo, recientemente encontré algunas publicaciones que trataban de imitar la funcionalidad MERGE de SQL Server 2008 utilizando una tabla temporal y el resultado de la declaración UPDATE.

Me interesó porque estoy investigando cómo puedo eliminar el tiempo en mi método Eliminar/Inserción masiva cuando la tabla no tiene filas. Todavía creo que este método será el más rápido, así que estoy buscando la mejor manera de resolver el problema de la mesa vacía.

Gracias

Respuesta

5

Creo que su método más rápido sería:

  1. gota todas las claves externas e índices desde su mesa.
  2. Truncate su tabla .
  3. A granel inserte sus datos.
  4. Vuelva a crear las claves externas y los índices .
+0

Gracias por las sugerencias, no sabía acerca de Truncate y probablemente lo use, pero estoy tratando de eliminar el corto período de tiempo entre la eliminación y la inserción masiva cuando la tabla está vacía. ¿Algunas ideas? – rpf3

+0

@ rpf3: Prueba TRUNCATE. Creo que eliminará gran parte de la demora de la que estás hablando. –

+0

El truncamiento fue definitivamente más rápido que el borrado, pero aún demora ~ 9 segundos para el inserto masivo. Me han preguntado si hay una manera de eliminar incluso esta pequeña cantidad de tiempo de inactividad porque otros procesos pueden afectar la base de datos durante el tiempo de ejecución. – rpf3

0

Para la velocidad bruta, creo que con ~ 150K filas en la tabla, simplemente dejaría caer la tabla, la volvería a crear desde cero (sin índices) y luego volvería a cargar a granel. Una vez que se haya realizado la carga masiva, cree los índices.

Esto supone, por supuesto, que tener un período de tiempo cuando la tabla está vacía/no existe es aceptable, lo que parece que podría ser el caso.

3

¿El problema es que la solución de Joe no es lo suficientemente rápida o que no puede tener actividad alguna en la tabla de destino mientras se ejecuta el proceso? Si solo necesita evitar que los usuarios ejecuten consultas en su tabla de destino, debe contener su proceso dentro de un bloque de transacción. De esta manera, cuando su TRUNCATE TABLE se ejecuta, se creará un bloqueo de tabla que se llevará a cabo durante la duración de la transacción, así:

begin tran; 

truncate table stage_table 

bulk insert stage_table 
from N'C:\datafile.txt' 

commit tran; 
+0

Estaba pensando en hacer esto, pero si no tienes permisos para acceder al archivo de datos o al archivo de formato, se produce un error que SQL TRY/CATCH no puede detectar y detiene el código a mitad de la transacción, dejándolo abierto. – rpf3

1

Una solución alternativa que satsify su requerimiento por no tener "tiempo de inactividad "para la tabla que estás actualizando.

Parece que originalmente estaba leyendo el archivo y haciendo una fila INSERT/UPDATE/DELETE 1 a la vez.Un enfoque más performant que eso, que no implica la limpieza de abajo de la tabla es la siguiente:

1) mayor cargar el archivo en una nueva, tabla separada (no hay índices)
2) a continuación, crear la PK en él
3) Ejecute 3 instrucciones para actualizar la tabla original de esta nueva tabla (temporal):
ELIMINAR filas en la tabla principal que no existen en la nueva tabla
ACTUALIZAR filas en la tabla principal donde hay una fila coincidente en la nueva tabla
INSERTAR filas en la tabla principal de la nueva tabla donde ya no existen

Esto funcionará mejor que las operaciones de fila por fila y debería cumplir con sus requisitos generales

+0

Gracias, voy a ejecutar algunas pruebas para ver si quiero usar esto o simplemente mantener la inserción masiva dentro de una transacción bloqueada por el corto tiempo de ejecución. – rpf3

1

Hay una forma de actualizar la tabla con tiempo de inactividad cero: mantenga los datos de dos días en la tabla y elimine las filas anteriores después de cargando los nuevos!

  1. Agregue una columna DataDate que represente la fecha para la cual sus ~ 150K filas son válidas.
  2. Crea una tabla de una fila y una columna con DataDate "de hoy".
  3. Cree una vista de las dos tablas que selecciona solo las filas que coinciden con la fila en la tabla DataDate. Indíquelo si lo desea. Los lectores ahora se referirán a esta vista, no a la tabla.
  4. A granel inserte las filas. (Obviamente tendrá que agregar el DataDate a cada fila.)
  5. Actualice la tabla DataDate. Ver actualizaciones ¡Al instante!
  6. Borra las filas de ayer cuando quieras.

SELECT rendimiento no sufrirá; unir una fila a 150,000 filas a lo largo de la clave principal no debería presentar ningún problema a ningún servidor con menos de 15 años de antigüedad.

He usado esta técnica a menudo y también he tenido problemas con los procesos que se basaban en sp_rename. Los procesos de producción que modifican el esquema son un dolor de cabeza. No lo hagas