Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > SQL
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 21-09-2010
TaaDow TaaDow is offline
Registrado
 
Registrado: sep 2010
Posts: 8
Poder: 0
TaaDow Va por buen camino
Arrow Vaciar contenido dataset a otro

Buen dia,
cuento con dos motores(db1-oracle y db2-sqlserver05), con unas tablas equivalentes, debo vaciar el contenido de una tabla db1 a db2, para ello, utilizo esta funcion a la cual le paso los dos datasets, origen y destino, que cuentan con las misma estructura:
Código Delphi [-]
procedure TForm1.CopiarRegistro(sql_Origen :TSimpleDataSet; sql_Destino :TSimpleDataSet);
var
  larr_Valores : Variant;
  lint_Cursor : Integer;
  x            : Integer;
begin
  
  sql_Destino.Open;
  sql_Origen.Open;

 while(not sql_Origen.Eof) do
  begin
    larr_Valores := VarArrayCreate([0,sql_Origen.Fieldcount-1],VarVariant);
    for lint_Cursor := 0 to (sql_Origen.Fieldcount-1) do
      larr_Valores[lint_Cursor] := sql_Origen.fields[lint_Cursor].Value ;
      sql_Destino.Append ;

    for lint_Cursor := 0 to (sql_Destino.Fieldcount-1) do
      sql_Destino.fields[lint_Cursor].Value := larr_Valores[lint_cursor] ;
      sql_Destino.Post;
    sql_Origen.Next;
      sql_Destino.ApplyUpdates(-1);
   
   end;
 end;
El procedimiento funciona, pero al ejecutarse, hago la prueba cargando en el dataset una tabla de 6 columnas y 50 mil filas, y ejecuta la tarea en mas de 7 horas, lo que me parece exagerado, dado que si subo un csv manualmente, con esa misma informacion, no toma mas de 30 minutos, es mi primera experiencia programando el delphi, desearia conocer sus opiniones con respecto a la eficiencia del codigo, es esta es la solucion mas optima?

Agradezco sus sugerencias al respecto.
Responder Con Cita
  #2  
Antiguo 21-09-2010
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Aún los 30 minutos para el csv que mencionas me parece demasiado. No debería tardar sino un par de minutos. Aunque desconozco los servidores que usas, supongo que tendrán alguna forma de desactivar los índices, que es lo que puede estar alentando el proceso.

Por otro lado, trabajar con variants siempres es más lento. En tu procedimiento podrías, por lo menos, ahorrarte el arreglo intermedio y hacer la asignación directa de un dataset a otro. Y si conoces la estructura de la tabla, sería mejor hacer las asignaciones con los métodos AsInteger, AsFloat, AsString, etc. de los objetos Field para evitar el uso de variants.

También, si tienes controles de edición conectados a los dataset, es mejor que uses los métodos DisableControls y EnableControls al hacer el traspaso, para que el proceso no se alente por la actualización visual de los datos.

// Saludos
Responder Con Cita
  #3  
Antiguo 21-09-2010
TaaDow TaaDow is offline
Registrado
 
Registrado: sep 2010
Posts: 8
Poder: 0
TaaDow Va por buen camino
Cita:
Aún los 30 minutos para el csv que mencionas me parece demasiado
la verdad estoy siendo algo exagerado

Cita:
Por otro lado, trabajar con variants siempres es más lento. En tu procedimiento podrías, por lo menos, ahorrarte el arreglo intermedio y hacer la asignación directa de un dataset a otro. Y si conoces la estructura de la tabla, sería mejor hacer las asignaciones con los métodos AsInteger, AsFloat, AsString, etc. de los objetos Field para evitar el uso de variants
esta manera me permite trabajar con diferentes tablas, de la forma que me sugieres, no tengo esa ventaja,

Cita:
También, si tienes controles de edición conectados a los dataset, es mejor que uses los métodos DisableControls y EnableControls al hacer el traspaso, para que el proceso no se alente por la actualización visual de los datos.
el unico control que utlizo es una barra de progreso, no creo que influya mucho en el asunto, es esta la forma mas ortodoxa, facil, viable,? de realizar el proceso de vaciado de tablas, que opinan? han utilizado el metodo clonecurosor?, no he podido hacerlo funcionar,

Gracias por su respuesta Roman.
Responder Con Cita
  #4  
Antiguo 21-09-2010
cloayza cloayza is offline
Miembro
 
Registrado: may 2003
Ubicación: San Pedro de la Paz, Chile
Posts: 913
Poder: 22
cloayza Tiene un aura espectacularcloayza Tiene un aura espectacular
Creo que la sugerencia del amigo Roman, es acertada.

La propiedad Value de un TFields es de tipo Variant, con lo cual el usar un vector de tipo Variant no tiene justificacion.

Ademas en cada ciclo de lectura de sql_Origen, estas dimensionando el vector, creo que eso se debe hacer antes de iniciar el ciclo de lectura una sola vez.

Alternativa 1:
Código Delphi [-]
procedure TForm1.CopiarRegistro(sql_Origen :TSimpleDataSet; sql_Destino :TSimpleDataSet);
var
  larr_Valores : Variant;
  lint_Cursor : Integer;
  x            : Integer;
begin
  
  sql_Destino.Open;
  sql_Origen.Open;
  larr_Valores := VarArrayCreate([0,sql_Origen.Fieldcount-  1],VarVariant);

 while(not sql_Origen.Eof) do
  begin
      for lint_Cursor := 0 to (sql_Origen.Fieldcount-1) do
      larr_Valores[lint_Cursor] := sql_Origen.fields[lint_Cursor].Value ;
      sql_Destino.Append ;

    for lint_Cursor := 0 to (sql_Destino.Fieldcount-1) do
      sql_Destino.fields[lint_Cursor].Value := larr_Valores[lint_cursor] ;
      sql_Destino.Post;

      sql_Origen.Next;
      sql_Destino.ApplyUpdates(-1);
   
   end;
 end;

Alternativa 2:
Código Delphi [-]
procedure TForm1.CopiarRegistro(sql_Origen :TSimpleDataSet; sql_Destino :TSimpleDataSet);
var
  lint_Cursor : Integer;
  x            : Integer;
begin
  
  sql_Destino.Open;
  sql_Origen.Open;
 while(not sql_Origen.Eof) do
  begin
        sql_Destino.Append ;

        for lint_Cursor := 0 to (sql_Destino.Fieldcount-1) do
             sql_Destino.fields[lint_Cursor].Value := sql_Origen.fields[lint_Cursor].Value;
        sql_Destino.Post;

        sql_Origen.Next;
        sql_Destino.ApplyUpdates(-1);
   
   end;
 end;
Saludos...
Responder Con Cita
  #5  
Antiguo 21-09-2010
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 29
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Hola TaaDow.

Lo que más lentitud le causa a ese ciclo es que en cada pasada estás llamando al método ApplyUpdates y éste internamente dispara la apertura y cierre automáticos de una trasacción —¡una transacción por registro!— en la base de datos destino (suponiendo que no hay ya una trasacción abierta antes de iniciar el proceso).

Coloca esa sentencia fuera (después) del While, con lo cual seguramente se reducirá significativamente el tiempo que consume la operación.

Dinos cómo te funciona de esa manera.

Un saludo.

Al González.
Responder Con Cita
  #6  
Antiguo 22-09-2010
TaaDow TaaDow is offline
Registrado
 
Registrado: sep 2010
Posts: 8
Poder: 0
TaaDow Va por buen camino
Cita:
Coloca esa sentencia fuera (después) del While, con lo cual seguramente se reducirá significativamente el tiempo que consume la operación.
,

Aplique la alternativa dos, siguiendo el consejo Al Gonzales, del applyupdates afuera del ciclo, despues de 5 horas en un 87% mi pc(w7,c2duo,3gb ram) se quedo sin memoria. procesando un dataset de 7 columnas por 52mil registros.

Tratare de dividir el dataset por paquetes mas pequeños, de 10mil o 5mil registros.

Gracias por sus respuestas.
Responder Con Cita
  #7  
Antiguo 22-09-2010
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 29
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Cita:
Empezado por TaaDow Ver Mensaje
...despues de 5 horas en un 87% mi pc(w7,c2duo,3gb ram) se quedo sin memoria. procesando un dataset de 7 columnas por 52mil registros...
Que extraño.

Después de lo que describes, pareciera como si nunca llegara a cumplirse la condición del While, vaya, como si la sentencia sql_Origen.Next no se ejecutara o algún evento moviera el cursor después de su acción.

¿Tienes manejadores de eventos asociados a sql_Origen?
Responder Con Cita
  #8  
Antiguo 22-09-2010
TaaDow TaaDow is offline
Registrado
 
Registrado: sep 2010
Posts: 8
Poder: 0
TaaDow Va por buen camino
Al Gonzales, gracias por contestar, cuando dejo el applyupdates adentro del while, es si termina de hacer el copiado, el problema es que se demora bastante, tengo asociado a la funcion solo una barra de progreso, y el boton que lanza la funcion, hago pruebas con 2000 registros y lo hace rapido, pero ya con esa carga, lo hace muy lento.
Código Delphi [-]
procedure TForm1.CopiarRegistro(sql_Origen :TSimpleDataSet; sql_Destino :TSimpleDataSet);
var
  lint_Cursor : Integer;
  x            : Integer;
begin

  sql_Destino.Open;
  sql_Origen.Open;

   self.cxProgressBar1.Clear;
  self.cxProgressBar1.Properties.Min:= 1;
  self.cxProgressBar1.Properties.Max:= sql_Origen.RecordCount;
  self.cxProgressBar1.Position:=1;

 while(not sql_Origen.Eof) do
  begin
        sql_Destino.Append ;

        for lint_Cursor := 0 to (sql_Destino.Fieldcount-1) do
             sql_Destino.fields[lint_Cursor].Value := sql_Origen.fields[lint_Cursor].Value;
        sql_Destino.Post;

        sql_Origen.Next;

        self.cxProgressBar1.Position:= self.cxProgressBar1.Position+1;
        self.cxProgressBar1.Refresh;
   
   end;
   sql_Destino.ApplyUpdates(-1);
 end;

es mi primer reto con delphi, no tengo el criterio o la suficiente experiencia para saber si es normal que se demore tanto, alguna sugerencia?
Responder Con Cita
  #9  
Antiguo 22-09-2010
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 29
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Cita:
Empezado por TaaDow Ver Mensaje
alguna sugerencia?
Una idea: ¿pasa lo mismo si comentas las sentencias que tienen que ver con la barra de progreso?
Responder Con Cita
  #10  
Antiguo 22-09-2010
chingolo chingolo is offline
Miembro
 
Registrado: feb 2008
Posts: 12
Poder: 0
chingolo Va por buen camino
porque no probas haciendo hilos de ejecucion?
o la manera mas facil es:

"INSERT INTO TU_TABLA_DESTINO VALUES (SELECT * FROM TU_TABLA_ORIGEN)"
esto copia todo el contenido del tu tabla origen a la de destino
luego haces un delete de tu talva origen y... listo el pollo pelada la gallina

Última edición por chingolo fecha: 22-09-2010 a las 05:41:22. Razón: mas info
Responder Con Cita
  #11  
Antiguo 22-09-2010
Avatar de Axel_Tech
Axel_Tech Axel_Tech is offline
Miembro
 
Registrado: nov 2008
Ubicación: lugar en que está ubicado algo.
Posts: 85
Poder: 16
Axel_Tech Va por buen camino
Cita:
Empezado por chingolo Ver Mensaje
porque no probas haciendo hilos de ejecucion?
o la manera mas facil es:

"INSERT INTO TU_TABLA_DESTINO VALUES (SELECT * FROM TU_TABLA_ORIGEN)"
esto copia todo el contenido del tu tabla origen a la de destino
luego haces un delete de tu talva origen y... listo el pollo pelada la gallina
Sería lo más fácil pero en este caso no se puede hacer eso porque son 2 tablas en 2 bd de distinto motor (Oracle y SQL Server).
A mí se me presentó una situción parecida (meter datos de una tabla de Access en una de Firebird) y lo hice de otra manera, aunque la idea es la misma: ir leyendo registro a registro de una e ir insertando en la otra. La principal diferencia radica en que no meto el valor de la propiedad Fields de un DataSet en el otro sino que leo un registro de la tabla origen, monto una cadena con un INSERT y lo meto en la tabla destino. Te muestro cómo, sólo que yo en vez de con TSimpleDataSet lo hice con Querys:

Código Delphi [-]
Query1.Active := False;
Query1.SQL.Clear;
Query1.SQL.Text = 'SELECT CAMPO1, CAMPO2, CAMPO3, CAMPO4, CAMPO5, CAMPO6 FROM TABLAORACLE';
Query1.Active := True;
Query1.First;

while not Query1.Eof do
  begin
    cad := '';
    cad := 'INSERT INTO TABLASQLSERVER (CAMPO1, CAMPO2, CAMPO3, CAMPO4, CAMPO5, CAMPO6) VALUES (';
    cad := cad + '' + Query1.FieldByName('CAMPO1').AsString + ',';
    cad := cad + '' + Query1.FieldByName('CAMPO2').AsString + ',';
    cad := cad + '' + Query1.FieldByName('CAMPO3').AsString + ',';
    cad := cad + '' + Query1.FieldByName('CAMPO4').AsString + ',';
    cad := cad + '' + Query1.FieldByName('CAMPO5').AsString + ',';
    cad := cad + '' + Query1.FieldByName('CAMPO6').AsString + ')';  //creamos la cadena con el insert into

    Query2.SQL.Clear;
    Query2.SQL.Text = cad;   //insertamos el nuevo registro
    Query2.ExecSQL;

    Query1.Next;
  end;

Más de 1600 registros con 5 columnas me lo hace en menos de 6 segundos, y mi equipo es bastante peor que el tuyo (AMD Sempron 1'8 Ghz y 512 de Ram) asique así a ojo lo tuyo no creo que tardara más de 4 minutos.

Por cierto, ¿no tendrás triggers before o after insert en la tabla de SQL Server? a ver si es que cada vez que insertas un registro se disparan y por eso te tarda tanto...
__________________
No hope, no dreams, no love, my only escape is Underground
Responder Con Cita
  #12  
Antiguo 22-09-2010
chingolo chingolo is offline
Miembro
 
Registrado: feb 2008
Posts: 12
Poder: 0
chingolo Va por buen camino
leyendo encontre esto:
Código SQL [-]
INSERT INTO BD2..destino SELECT * FROM BD1..origen
obviamente con los mismo campos
Responder Con Cita
  #13  
Antiguo 22-09-2010
TaaDow TaaDow is offline
Registrado
 
Registrado: sep 2010
Posts: 8
Poder: 0
TaaDow Va por buen camino
Con la funcion de los dos datasets, puedo hacer el vaciado pero, es muy lento proceso, hice algo similar a lo que propone axeltech, con dos TSQLquery, y construir los inserts, funciona, se demoro 3 minutos, con los 51000 registros, lo unico que no me parece es lo estatico del codigo, pero igual, esta bien, son cuatro tablas diferentes, aplicare un switch case evaluando los casos.

De antemano, roman, cloayza,Al González, Axel_Tech, chingolo, gracias por las respuestas, fueron de gran ayuda. creo que ya se puede cerrar el tema.

TaaDow.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Copiar el contenido de un DataSet a otro DataSet Javi2 Varios 82 22-11-2022 09:26:16
Actualizar un dataset desde otro dataset jafera Conexión con bases de datos 17 18-12-2008 23:57:10
Conectar a un DataSet de otro form. DarkByte Conexión con bases de datos 15 10-09-2004 16:27:58
Vaciar el contenido de un directorio (Borrar *.*) Gelmin Varios 1 22-07-2004 20:21:50
Saber si un Tabla(dataset) esta siendo usado por otro componente cacuna OOP 3 26-05-2004 18:21:43


La franja horaria es GMT +2. Ahora son las 08:59:58.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi