Borrar gran cantidad de registro

Borrar gran cantidad de registro

Postby manuelcalerosolis » Tue Nov 08, 2011 10:25 am

Hola a tod@s

Me estoy encontrando con una problemática q nunca se me había dado y es q tengo un cliente q manipula una gran cantidad de registros en sus operaciones.

Por ejemplo puede llegar a meter 275.000 lineas de registros en los números de series de una factura, según mi sistema de mantenimiento yo elimino los registro de la base de datos anterior a la edición y a renglón seguido añado las lineas a la tabla definitiva desde una tabla temporal.

Pero claro en tanto numero de registros los tiempo se hacen enormes, y me preguntaba si hay manera de realizar el borrado de registros de 275.000 registros de manera muy muy rápida, yo actualmente lo hago así.

if cKey != nil

while ::oDbf:Seek( cKey )

if ::bOnPreDeleteDetail != nil
Eval( ::bOnPreDeleteDetail, Self )
end if

::oDbf:Delete( .f. )

if ::bOnPostDeleteDetail != nil
Eval( ::bOnPostDeleteDetail, Self )
end if

end while

end if

pero claro el bucle puede ejecutarse 275.000 veces o mas, como puedo borrar de un tirón todos los registros q cumplan una condición de manera mas efectiva.

Gracias.
User avatar
manuelcalerosolis
 
Posts: 149
Joined: Mon Oct 10, 2005 9:30 am
Location: Huelva - Spain

Re: Borrar gran cantidad de registro

Postby hmpaquito » Tue Nov 08, 2011 11:13 am

Manuel,

Necesitas un indice por la condicion de borrado y para mas velocidad no uses la clase TDatabase, sino las primitivas rdd.
El bucle basico es el de siempre:

Code: Select all  Expand view


// Ejemplo
#Define lCONDICION_BORRADO (TotalCobrado > TotalFactura)


/*
El indice (permanente) que se ha de crear es
INDEX ON If(lCONDICION_BORRADO, "S", "N") TO Nombre_indice

donde lCONDICION_BORRADO se explica por sí misma

*/




SELECT (cAlias)
// nOrderIndiceCondicionBorrado: Orden para recorrer SOLO los que cumplen la condicion de borrado
SET ORDER TO nOrderIndiceCondicionBorrado  
SEEK "S"
DO WHILE !Eof() .AND. lCONDICION_BORRADO
   Rec_Lock(0)
   DELETE
   SKIP
ENDDO
UNLOCK
 


Saludos
hmpaquito
 
Posts: 1482
Joined: Thu Oct 30, 2008 2:37 pm

Re: Borrar gran cantidad de registro

Postby manuelcalerosolis » Tue Nov 08, 2011 11:20 am

En ese caso perdería tiempo creando el indice, de todas maneras hago la prueba y computo los tiempos.

Gracias.-
User avatar
manuelcalerosolis
 
Posts: 149
Joined: Mon Oct 10, 2005 9:30 am
Location: Huelva - Spain

Re: Borrar gran cantidad de registro

Postby hmpaquito » Tue Nov 08, 2011 12:11 pm

Manuel,

En mi anterior post escribí:

"El indice (permanente) que se ha de crear es
INDEX ON If(lCONDICION_BORRADO, "S", "N") TO Nombre_indice."

Es decir, lo que yo te proponia es que añadas de forma permanente ese indice a la coleccion de indices (u ordenes) que tenga la tabla, asi el indice estará preparado para ser usado.

Saludos
hmpaquito
 
Posts: 1482
Joined: Thu Oct 30, 2008 2:37 pm

Re: Borrar gran cantidad de registro

Postby manuelcalerosolis » Tue Nov 08, 2011 12:56 pm

Eso no es posible pq los registros q yo borro son los q el usuario decida editar, no puedo tener un indice por cada documento q yo cree.

Saludos.
User avatar
manuelcalerosolis
 
Posts: 149
Joined: Mon Oct 10, 2005 9:30 am
Location: Huelva - Spain

Re: Borrar gran cantidad de registro

Postby hmpaquito » Tue Nov 08, 2011 1:43 pm

Manuel,

Es que no entiendo muy bien; vamos a ver:

Si por ejemplo la tabla de marras tiene un campo Editado .T./.F., que indica si un documento ha sido editado, entonces el indice se creara asi:

INDEX ON If(Editado, "S", "N") TO IndEdi


Saludos
hmpaquito
 
Posts: 1482
Joined: Thu Oct 30, 2008 2:37 pm

Re: Borrar gran cantidad de registro

Postby RodolfoRBG » Tue Nov 08, 2011 9:10 pm

y que tal haciendolo como se hacia en dBase3:

DELE ALL FOR (Condicion)
PACK
RodolfoRBG
FWH 1307, xHarbour123 BCC582
rodolfoerbg@gmail.com
User avatar
RodolfoRBG
 
Posts: 257
Joined: Tue May 16, 2006 4:46 pm
Location: San Luis Potosi, SLP, Mexico

Re: Borrar gran cantidad de registro

Postby Enrrique Vertiz » Tue Nov 08, 2011 10:01 pm

Bueno con ese volumen de informacion, mi sugerencia seria trabajar con algun motor como MySQL, ahi las sentencias de borrado son inmediatas, DELETE FROM ...... WHERE y no necesitan apertura exclusiva, ni indices especiales, pero claro habria que migrar, solo una idea ...
Enrrique Vertiz Pitta
Lima-Peru
xHb 1.23.1026X, Fwh 24.02, MySQL 8.0.X, SQLLIB 1.9m
Enrrique Vertiz
 
Posts: 519
Joined: Fri Oct 07, 2005 2:17 pm
Location: Lima - Peru

Re: Borrar gran cantidad de registro

Postby lucasdebeltran » Wed Nov 09, 2011 9:21 am

Manuel,

¿Has cambiado de página?. Apolosoftware ya no funciona.

Un saludo
Muchas gracias. Many thanks.

Un saludo, Best regards,

Harbour 3.2.0dev, Borland C++ 5.82 y FWH 13.06 [producción]

Implementando MSVC 2010, FWH64 y ADO.

Abandonando uso xHarbour y SQLRDD.
User avatar
lucasdebeltran
 
Posts: 1303
Joined: Tue Jul 21, 2009 8:12 am

Re: Borrar gran cantidad de registro

Postby manuelcalerosolis » Wed Nov 09, 2011 11:19 am

Lo de pasar a SQL es complicado mi programa tiene muchísimo código fuente me plantee en tiempo pasar a ADS Cliente/Servidor y los resultados q obtube no fueron muy buenos. Quizás sea momento de volver a intentarlo.

Otra idea era pasar a SQLRDD para xH las pruebas q hice me dejaron muy contento.

Lucas si hemos tenido un problema con el proveedor del dominio y ahora estamos en www.gstrotor.com estamos intentando recuperar nuestro dominio pero de momento no lo hemos conseguido.

Gracias a todos.
User avatar
manuelcalerosolis
 
Posts: 149
Joined: Mon Oct 10, 2005 9:30 am
Location: Huelva - Spain

Re: Borrar gran cantidad de registro

Postby MarioG » Wed Nov 09, 2011 2:06 pm

Manuel;
Esto es lo que desarrollé alguna vez, utilidando DbSix + TDbf, aunque no tengo experiencia con el borrado de una cantidad de registros como el que mencionas

Code: Select all  Expand view
...
           oDbf_2:= fAbreDbf( DB_ANPRC, FALSE )   // Abro la DB en modo exclusivo
                                                                                        // Campo CodItm
           MsgMeter( {|oMeter,oTxt| fBorrando( oMeter, oTxt, oDbf_2, cCodigo, nEs, DB_ANPRC, 1 ) }, ;
                                               "", "Borrando...")
           oDbf_2:End()       // la cierro, porque es de la época q se cerraba luego de su uso
...

// ---------------------------------------------------------------------------------------------
static procedure fBorrando( oMeter, oTxt, oDbf, cCodigo, nEsPadre, nEs, nCampo )    // No todos los parámetros son útiles en este sample
local bMeter, ;
...

// Odómetro
   bMeter:= {|| oMeter:Set( nRecNos ), ;
                SysRefresh(),          ;
                nRecNos += if( oMeter:nTotal >= 2500, 10, 1) }

   oMeter:nTotal:= oDbf:LastRec()
   nRecNos:= if( oMeter:nTotal >= 2500, 10, 1)      // segun el total de registros muestra el avance del meter
   oTxt:SetText( cMsgMet )

      (oDbf:nArea)->( dbEval( {|| if( cCodigo == Left( oDbf:FieldGet( nCampo ), 3), (oDbf:Delete(), nBorrados++ ), ), ;
                                  nEval++, ;
                                  if( nRecNos!=nEval, , Eval( bMeter ) ) } ) )
   end
   oTxt:SetText( "Se Borraron "+Str(nBorrados,5)+" Registros" )
   oMeter:Set( oMeter:nTotal )
   oMeter:Refresh()
   SysRefresh()
   Inkey( 2 )        // Una parada traida de Clipper :)


Aqui no proceso ni con bFor, ni con bWhile porque cada DB estaba ordenada por su cCodigo
Como comentario adicional te comento que, en el Foro, hay un post de alguien que hizo unas comprativas entre procesar eventos con ADSSQL - FOR EACH y, DbEval, y la diferencia era mínima.

Saludos
Resistencia - "Ciudad de las Esculturas"
Chaco - Argentina
User avatar
MarioG
 
Posts: 1380
Joined: Fri Oct 14, 2005 1:28 pm
Location: Resistencia - Chaco - AR

Re: Borrar gran cantidad de registro

Postby Carlos Mora » Wed Nov 09, 2011 3:39 pm

Si usas los métodos de la clase TDatabase para hacer actualizaciones, seguramente se empezarán
a notar todas las cosas extras que hace cada método y de las que muchas veces podemos prescindir.
Prueba a usar el siguiente código, no se me ocurre nada más rápido que esto. No sé bien que hacen
los métodos bOnPreDeleteDetail y bOnPostDeleteDetail, pero si hacen uso de la clase tdatabase
considera hacer el mismo cambio. Haz una prueba y compara los tiempos.
La forma de bloquear y desbloquear es un poco más agresiva, pero seguramente compensa con la diferencia de tiempos.
Que rdd usas? Que clave tiene el índice? Alguna condición FOR? Se me ocurre que por ahí también podría
estudiarse alguna forma de optimización, tipo un FOR !Deleted() o cosas así.

Code: Select all  Expand view

if cKey != nil
   
   Select ( oDbf:nArea )
   
   FLock() // Acá seguramente tienes algo para bloquear todo el fichero en lugar de la FLock

   while dBSeek( cKey ) // con lSoft si corresponde

      if ::bOnPreDeleteDetail != nil
         Eval( ::bOnPreDeleteDetail, Self )
      end if

      dBDelete()

      if ::bOnPostDeleteDetail != nil
         Eval( ::bOnPostDeleteDetail, Self )
      end if

   end while

   dBCommit()
   dBUnLock()

end if

 
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
Carlos Mora
 
Posts: 988
Joined: Thu Nov 24, 2005 3:01 pm
Location: Madrid, España

Re: Borrar gran cantidad de registro

Postby manuelcalerosolis » Thu Nov 10, 2011 8:38 am

Carlos,

Todos los indices tienen la condición !Deleted(), el valor q contiene el indice es la suma de los campos series + numero + delación + numero de linea no es muy extenso.

Saludos.
User avatar
manuelcalerosolis
 
Posts: 149
Joined: Mon Oct 10, 2005 9:30 am
Location: Huelva - Spain

Re: Borrar gran cantidad de registro

Postby hmpaquito » Thu Nov 10, 2011 9:57 am

Manuel,

Te intenté ayudar y no respondiste a mi último mensaje. Se conoce que ya has encontrado la solucion a tu problema.
Uno se siente satisfecho por poder ayudar y encontrar el agradecimiento oportuno.

Saludos
hmpaquito
 
Posts: 1482
Joined: Thu Oct 30, 2008 2:37 pm

Re: Borrar gran cantidad de registro

Postby ermatica » Thu Nov 10, 2011 3:10 pm

Hola Manuel,

No se si ya lo tienes solucionado, de todas formas te comento.
Lo del indice en el caso que te expongo si sería obligatorio, pero usaria scope.

He montado una tabla con un indice (.NTX) con 300.000 registros, filtro entre los registros a borrar y en un ordenador en local los tiempos que me muestra
con un msgalert (Time() ) son de 14:57:35 y final 14:57:49. No se si es mucho. El código que usé es:

Code: Select all  Expand view
 cAlias2:=OpenDbf(mPath_Fich+"FHCARCK1.DBF",5,.T.,.F.,.F.,{mPath_Fich+"FHCARCK1.NTX"},"DBFNTX")
  If cAlias2=""
     return nil
  endif
  Select (cAlias2)
  OrdsetFocus(1)
  dbgotop()

  ordscope(0,)  // quitar scope, filtro o rango
  ordscope(1,)
  dbgotop()

  nReg0 :=   1000
  nReg1 := 300000
 
  ordscope(0,nReg0)  // poner scope, filtro o rango
  ordscope(1,nReg1)
  dbgotop()

msgalert ( time() )
  Do While !Eof()
     Do While !Rlock()
      msgalert ("Registro en uso")
      Return
     Enddo
     (cAlias2)->(dbdelete())
     skip
  Enddo

msgalert ( time() )
 


Un cordial saludo,
Ernesto
ermatica
 
Posts: 44
Joined: Mon Nov 12, 2007 1:50 pm
Location: España

Next

Return to FiveWin para Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 54 guests