2012-09-13 26 views
6

Necesito mejorar el rendimiento de la carga de datos. El algoritmo actual hace una selección completa de una tabla:¿Cómo mejorar el rendimiento de inserción/actualización de datos?

select Field1, Field2,...,FieldN from Table1 order by FieldM 

Los nuevos datos se leen desde un archivo de texto (por ejemplo, archivo de texto línea por línea tabla de datos). La tabla tiene una clave principal, que contiene dos campos. Para cada línea de un archivo de texto, localiza la fila necesaria en estos dos campos (es decir, la clave principal).

query.Locate('Field1;Field2',VarArrayOf([Value1,Value2]),[]); 

If Locate vuelve True, que edita la fila, de lo contrario, añade una nueva.

Por lo tanto, en la medida en que la tabla consta de aproximadamente 200000 filas, cada operación Locate lleva cierto tiempo ... por lo que se las arregla para actualizar alrededor de 5-6 filas por segundo.

¿Qué cosas debo considerar para mejorarlo?

¿Probablemente cambie la localización a través de esta gran selección con consultas separadas?

Respuesta

10

NO utilice Locate(). Si utiliza locate(), Delphi busca la fila en el lado del cliente, simplemente escaneando el conjunto de filas de su consulta, se necesita MUCHO tiempo.

Si tiene acceso a MSSQL para crear procedimientos almacenados, cree el siguiente procedimiento y simplemente ejecútelo para cada línea desde su archivo de texto sin condiciones (use TAdoStoredProc.ExecProc en Delphi). Entonces, en este caso, no necesita primero seleccionar y localizar el procedimiento. Actualiza el registro si se encuentra Filed1 y Field2 e inserta si no lo hace.

CREATE PROCEDURE dbo.update_table1 
@Field1 int, --key1 
@Field2 int, --key2 
@Field3 int, -- data fileds 
@Field4 int 

AS 

SET NOCOUNT ON 
update table1 set [email protected],[email protected] 
     where [email protected] and [email protected]; 
IF(@@Rowcount=0) 
BEGIN 
    insert into table1(Field1,Field2,Field3,Field4) 
       values (@Field1,@Field2,@Field3,@Field4); 
END 
GO 

Aquí es código de Delphi para invocar este procedimiento almacenado con ADO:

...... 
var 
    ADOStoredP: TADOStoredProc; 

    ...... 
begin 

........ 
    ADOStoredP:=TADOStoredProc.Create(nil); 
    try 
     ADOStoredP.Connection:=DataMod.SQL_ADOConnection; //Your ADO Connection instance here 
     ADOStoredP.ProcedureName:='Update_table1'; 
     ADOStoredP.Parameters.CreateParameter('@Field1', ftInteger, pdInput, 0, 0); 
     ADOStoredP.Parameters.CreateParameter('@Field2', ftInteger, pdInput, 0, 0); 
     ADOStoredP.Parameters.CreateParameter('@Field3', ftInteger, pdInput, 0, 0); 
     ADOStoredP.Parameters.CreateParameter('@Field4', ftInteger, pdInput, 0, 0); 

     While() -- Your text file loop here 
     begin 

     ADOStoredP.Parameters.ParamByName('@Field1').Value:=Field1 value from text file here; 
     ADOStoredP.Parameters.ParamByName('@Field2').Value:=Field2 value from text file here; 
     ADOStoredP.Parameters.ParamByName('@Field3').Value:=Field3 value from text file here; 
     ADOStoredP.Parameters.ParamByName('@Field4').Value:=Field4 value from text file here; 

     ADOStoredP.ExecProc; 

     end 

    finally 
     if Assigned(ADOStoredP) then 
     begin 
     ADOStoredP.Free; 
     end; 
    end; 

........ 
end; 
+3

Esta solución redujo el tiempo de carga de 4 horas a menos de 4 minutos. ¡Realmente aprecio tu ayuda! ¡Gracias! – horgh

5
  1. Si es posible, entonces debe enviar el archivo de texto al servidor que ejecuta SQL Server. A continuación, utilice OPENROWSET(BULK) para abrir el archivo de texto (consulte "E. Uso del proveedor OPENROWSET BULK con un archivo de formato para recuperar filas de un archivo de texto").
  2. Si no puede enviar el archivo de texto al servidor, cree una tabla de base de datos temporal o persistente y use INSERT para insertar todas las filas de archivos de texto en la tabla.
  3. Si está utilizando SQL Server 2008, debe usar el operador MERGE. Si hay más versiones antiguas de SQL Server, puede usar dos comandos SQL: ACTUALIZAR e INSERTAR. Y como fuente de datos utilice (1) OPENROWSET o (2) tabla DB.
+0

pesar de que era mucho más fácil aplicar la respuesta por valex a mi situación, gracias por la ayuda. El servidor sql de destino es incluso 2000. Una muy antigua. Rehacer todo el algoritmo para cargar archivos en una tabla temporal (y así sucesivamente ...) no vale la pena el rendimiento (si lo hay) en comparación con lo que logré (y cuánto tiempo gasté para ello) gracias a la idea de valex . ¡Gracias de todos modos! – horgh

Cuestiones relacionadas