Discussion:
mejor opcion para procesar gran volumen de una BD?
(demasiado antiguo para responder)
Pablo
2009-11-26 02:13:01 UTC
Permalink
Tengo tres tablas:

VEN (clave primaria=id)
LIQ (clave primaria=id)
Conc (clave primaria=id)

Las tablas Ven y Liq tienen muchos muchicimos registros (seguramente no
alcance la memoria para leerlos)
en estado pendiente. Ademas tienen muchos campos cada una.

Lo que tengo que hacer es:
Un join entre LIQ y VEN (por unos 4 o 5 campos) y de ese join recuperar
apenas un grupo de campos.

Y por cada par que encuentro, grabar un registro en CONC.
Al grabar el CONC me devolvera su ID.

Ademas debo actualizar el par (ese LIQ y ese VENC) completandoles a cada uno:
- Un campo con un valor de una fecha que voy calculando (llamemosla fecha1)
- Un campo con un valor de una fecha que voy calculando (llamemosla fecha2)
- Un campo con un valor de una fecha que voy calculando (llamemosla fecha3)
- Un campo ID llamado ID_CONC que tiene el valor del ID obtenido al grabar
CONC

Como puedo hacer?
Uso un datareader? un dataset? otra idea?

Imagino Que me conviene leer de a lotes, tipo de a 1000 pares o algo asi
(de a uno seria muy lento y todo junto tal vez no alcance la memoria)

Y... (espero no abusar con mi consulta) ¿tienen algun ejemplo?

PD: APLICACION WINDOWS, NO ASP


Uso c# y la base puede ser SQLSERVER (DISTINTAS VERSIONES) U (ORACLE)
Para salir del paso, si la solucion aplica solo a sqlserver me va sirviendo
por ahora.
Heeelp

Gracias
refpxp25112009
Alberto Poblacion
2009-11-26 07:44:47 UTC
Permalink
Post by Pablo
Un join entre LIQ y VEN (por unos 4 o 5 campos) y de ese join recuperar
apenas un grupo de campos.
Y por cada par que encuentro, grabar un registro en CONC.
Al grabar el CONC me devolvera su ID.
- Un campo con un valor de una fecha que voy calculando (llamemosla fecha1)
- Un campo con un valor de una fecha que voy calculando (llamemosla fecha2)
- Un campo con un valor de una fecha que voy calculando (llamemosla fecha3)
- Un campo ID llamado ID_CONC que tiene el valor del ID obtenido al grabar
CONC
Como puedo hacer?
Uso un datareader? un dataset? otra idea?
Si son muchos registros, preferiblemente un DataReader, para procesarlos
secuencialmente y no tener que cargar mucha información en memoria. Yo lo
haría asi:

1) Construir una consulta Select con un JOIN de LIQ y VEN, para recuperar el
grupo de campos deseado.
2) Abrir el resultado de esa consulta con un DataReader, y procesarlos en un
bucle.
3) Por cada registro recibido, hacer una grabación en CONC (con un INSERT
seguido de un Select que recupere el ID)
4) Actualizar en LIQ y VENC los datos indicados más arriba (con UPDATE).
5) Pasar al siguiente registro en el bucle que está leyendo del DataReader
original.

Hay que tener en cuenta que para el paso 3 y el paso 4 se necesita
utilizar una segunda conexión al servidor de base de datos. No se puede usar
la misma conexión que se empleó en el paso 2 porque el DataReader la
mantiene ocupada. Alternativamente, se podría usar MARS al abrir la
conexión, y entonces bastaría con una, pero MARS solo funciona con Sql
Server 2005 o posterior.
Pablo
2009-12-09 20:52:52 UTC
Permalink
Entonces avance por ese camino.

Pero, cada x registros (voy haciendo commit cada 100, cosa de que si falla,
lo procesado procesado esta, al menos la mayoria), y aleatoreamente me da
timeout.

No queria llegar a la solución simple de aumentar el timeout, ya que el
proceso actual (si bien trabaja de otra forma) hace los mismos update y los
mismos insert que este, y no da timeout.

La diferencia es que la aplicación actual, trabaja mas despacio y hace un
solo commit al final. (levanta todo a memoria y va joineando de a poco y a
medida que coinciden hace los update y commits)

En cambio, este proceso nuevo, trabaja muchisimo más rapido (con mejoras de
hasta el 98%) pero cada tanto, una sentencia update de liq se "cuelga" un
buen rato y salta por timeout. ¿sera que trabaja tan rapido que la base de
datos no hace a tiempo a extenderse en disco o algo asi?

Se te ocurre algo adicional a extender el timeout?
Post by Alberto Poblacion
Post by Pablo
Un join entre LIQ y VEN (por unos 4 o 5 campos) y de ese join recuperar
apenas un grupo de campos.
Y por cada par que encuentro, grabar un registro en CONC.
Al grabar el CONC me devolvera su ID.
- Un campo con un valor de una fecha que voy calculando (llamemosla fecha1)
- Un campo con un valor de una fecha que voy calculando (llamemosla fecha2)
- Un campo con un valor de una fecha que voy calculando (llamemosla fecha3)
- Un campo ID llamado ID_CONC que tiene el valor del ID obtenido al grabar
CONC
Como puedo hacer?
Uso un datareader? un dataset? otra idea?
Si son muchos registros, preferiblemente un DataReader, para procesarlos
secuencialmente y no tener que cargar mucha información en memoria. Yo lo
1) Construir una consulta Select con un JOIN de LIQ y VEN, para recuperar el
grupo de campos deseado.
2) Abrir el resultado de esa consulta con un DataReader, y procesarlos en un
bucle.
3) Por cada registro recibido, hacer una grabación en CONC (con un INSERT
seguido de un Select que recupere el ID)
4) Actualizar en LIQ y VENC los datos indicados más arriba (con UPDATE).
5) Pasar al siguiente registro en el bucle que está leyendo del DataReader
original.
Hay que tener en cuenta que para el paso 3 y el paso 4 se necesita
utilizar una segunda conexión al servidor de base de datos. No se puede usar
la misma conexión que se empleó en el paso 2 porque el DataReader la
mantiene ocupada. Alternativamente, se podría usar MARS al abrir la
conexión, y entonces bastaría con una, pero MARS solo funciona con Sql
Server 2005 o posterior.
.
Alberto Poblacion
2009-12-10 10:27:07 UTC
Permalink
Post by Pablo
Entonces avance por ese camino.
Pero, cada x registros (voy haciendo commit cada 100, cosa de que si falla,
lo procesado procesado esta, al menos la mayoria), y aleatoreamente me da
timeout.
No queria llegar a la solución simple de aumentar el timeout, ya que el
proceso actual (si bien trabaja de otra forma) hace los mismos update y los
mismos insert que este, y no da timeout.
La diferencia es que la aplicación actual, trabaja mas despacio y hace un
solo commit al final. (levanta todo a memoria y va joineando de a poco y a
medida que coinciden hace los update y commits)
En cambio, este proceso nuevo, trabaja muchisimo más rapido (con mejoras de
hasta el 98%) pero cada tanto, una sentencia update de liq se "cuelga" un
buen rato y salta por timeout. ¿sera que trabaja tan rapido que la base de
datos no hace a tiempo a extenderse en disco o algo asi?
Se te ocurre algo adicional a extender el timeout?
Revisa el código, a ver si se te está quedando alguna conexión sin
cerrar. Si a cada vuelta del bucle abres la conexión para hacer la grabación
(o si lo haces cada 100 veces, cuando haces el commit), y se te queda esa
conexión sin cerrar, vas consumiendo conexiones del Pool, y al llegar a la
100 e intentar abrir la 101, se queda esperando a que se cierre una de las
100 anteriores, y como no se cierra, te acaba dando un timeout.
Pablo
2009-12-10 12:33:01 UTC
Permalink
Acabo de revisar el código y aparentemente la conexión se abre en cada ciclo
y se cierra en cada ciclo correctamente.

Probe ir ejecutando "EXEC SP_WHO " y la cantidad de conexiones del usuario
es constante, siempre son cuatro. ¿eso me indicaría que estoy cerrando todo
no? O se me puede estar pasando algo?

Otro dato: Si acorto el ciclo (es decir, en lugar de abrir, grabar, comitear
cada cien registros) lo hago de a UN (1) registro, veo que cuando falla,
pincha un registro, pincha el siguiente, el siguiente, asi 3 o 4. Luego
sigue como si nada, avanza un buen volumen y vuelve a fallar dos o tres
registros seguidos.
Post by Alberto Poblacion
Post by Pablo
Entonces avance por ese camino.
Pero, cada x registros (voy haciendo commit cada 100, cosa de que si falla,
lo procesado procesado esta, al menos la mayoria), y aleatoreamente me da
timeout.
No queria llegar a la solución simple de aumentar el timeout, ya que el
proceso actual (si bien trabaja de otra forma) hace los mismos update y los
mismos insert que este, y no da timeout.
La diferencia es que la aplicación actual, trabaja mas despacio y hace un
solo commit al final. (levanta todo a memoria y va joineando de a poco y a
medida que coinciden hace los update y commits)
En cambio, este proceso nuevo, trabaja muchisimo más rapido (con mejoras de
hasta el 98%) pero cada tanto, una sentencia update de liq se "cuelga" un
buen rato y salta por timeout. ¿sera que trabaja tan rapido que la base de
datos no hace a tiempo a extenderse en disco o algo asi?
Se te ocurre algo adicional a extender el timeout?
Revisa el código, a ver si se te está quedando alguna conexión sin
cerrar. Si a cada vuelta del bucle abres la conexión para hacer la grabación
(o si lo haces cada 100 veces, cuando haces el commit), y se te queda esa
conexión sin cerrar, vas consumiendo conexiones del Pool, y al llegar a la
100 e intentar abrir la 101, se queda esperando a que se cierre una de las
100 anteriores, y como no se cierra, te acaba dando un timeout.
.
Alberto Poblacion
2009-12-10 12:58:56 UTC
Permalink
Post by Pablo
Acabo de revisar el código y aparentemente la conexión se abre en cada ciclo
y se cierra en cada ciclo correctamente.
Probe ir ejecutando "EXEC SP_WHO " y la cantidad de conexiones del usuario
es constante, siempre son cuatro. ¿eso me indicaría que estoy cerrando todo
no? O se me puede estar pasando algo?
Efectivamente, si el sp_who dice que solo hay cuatro conexiones, no te
las estás dejando abiertas. Tiene que ser alguna otra cosa.
Post by Pablo
[...] Si acorto el ciclo (es decir, en lugar de abrir, grabar, comitear
cada cien registros) lo hago de a UN (1) registro, veo que cuando falla,
pincha un registro, pincha el siguiente, el siguiente, asi 3 o 4. Luego
sigue como si nada, avanza un buen volumen y vuelve a fallar dos o tres
registros seguidos.
La verdad es que resulta bastante raro. Si tienes una versión "grande"
de Sql Server (no la Express), puedes probar a capturar las sentencias con
el Profiler. Márcale al Profiler en la pestaña de opciones todas las que
sean relevantes, tales como número de operaciones de entrada/salida, tiempo
de CPU, bloqueos, etc., a ver si a la vista de las sentencias que está
capturando y de los datos de ejecución de dichas sentencias te da alguna
pista de qué puede estar pasando.
Pablo
2009-12-10 17:46:01 UTC
Permalink
Post by Alberto Poblacion
Post by Pablo
Acabo de revisar el código y aparentemente la conexión se abre en cada ciclo
y se cierra en cada ciclo correctamente.
Probe ir ejecutando "EXEC SP_WHO " y la cantidad de conexiones del usuario
es constante, siempre son cuatro. ¿eso me indicaría que estoy cerrando todo
no? O se me puede estar pasando algo?
Efectivamente, si el sp_who dice que solo hay cuatro conexiones, no te
las estás dejando abiertas. Tiene que ser alguna otra cosa.
Post by Pablo
[...] Si acorto el ciclo (es decir, en lugar de abrir, grabar, comitear
cada cien registros) lo hago de a UN (1) registro, veo que cuando falla,
pincha un registro, pincha el siguiente, el siguiente, asi 3 o 4. Luego
sigue como si nada, avanza un buen volumen y vuelve a fallar dos o tres
registros seguidos.
La verdad es que resulta bastante raro. Si tienes una versión "grande"
de Sql Server (no la Express), puedes probar a capturar las sentencias con
el Profiler. Márcale al Profiler en la pestaña de opciones todas las que
sean relevantes, tales como número de operaciones de entrada/salida, tiempo
de CPU, bloqueos, etc., a ver si a la vista de las sentencias que está
capturando y de los datos de ejecución de dichas sentencias te da alguna
pista de qué puede estar pasando.
.
Probe poner timeout en cero para poder ver en que quedaba colgado. Lo que
veo, es que me da con sp_who que esta en estado SUSPENDIDO.
Ejecutando el profiler (primera vez que lo hago) lo que noto es que la linea
amarilla (paginas) ¿memoria? se va arriba y queda contra el tope
No se interpretar el resultado.
Buscando veo que el estado suspendido en sqlserver 2005 podria solucionarse
con el SP2, lo aplique pero nada, sigue igual.
Alberto Poblacion
2009-12-10 22:07:30 UTC
Permalink
Post by Pablo
Ejecutando el profiler (primera vez que lo hago) lo que noto es que la linea
amarilla (paginas) ¿memoria? se va arriba y queda contra el tope
No, es es el Profiler de Windows. Me refería al "Sql Server Profiler",
que viene en la carpeta de "Performance Tools" del Sql Server en el menú de
inicio. Este te captura las sentencias SQL que llegan al servidor, junto con
todas las estadísticas de cómo se ejecutó cada sentencia. Mi sospecha es que
pueda haber problemas de bloqueos debidos a las transacciones; pretendía
capturar esta situación con el Sql Profiler. Otra forma de saber si es
problema de bloqueos es llamar a sys.dm_tran_locks justo cuando dé el
timeout, a ver si hay cosas bloqueadas a las que está tratando de acceder la
sentencia que da timeout.
Pablo
2009-12-11 01:52:01 UTC
Permalink
Post by Alberto Poblacion
Post by Pablo
Ejecutando el profiler (primera vez que lo hago) lo que noto es que la linea
amarilla (paginas) ¿memoria? se va arriba y queda contra el tope
No, es es el Profiler de Windows. Me refería al "Sql Server Profiler",
que viene en la carpeta de "Performance Tools" del Sql Server en el menú de
inicio. Este te captura las sentencias SQL que llegan al servidor, junto con
todas las estadísticas de cómo se ejecutó cada sentencia. Mi sospecha es que
pueda haber problemas de bloqueos debidos a las transacciones; pretendía
capturar esta situación con el Sql Profiler. Otra forma de saber si es
problema de bloqueos es llamar a sys.dm_tran_locks justo cuando dé el
timeout, a ver si hay cosas bloqueadas a las que está tratando de acceder la
sentencia que da timeout.
.
Sabes, parece que el problema viene por otro lado. Tuve que ejecutar otras
sentencias y me esta fallando toda la aplicación de golpe.
En otra PC, el mismo ejecutable no me falla. Pero en la mia, con el
sqlserver que tengo me da timeout en cuanto la fuerzo un poco.
Probe exportar e importar la base en otra PC y anduvo bien. Mismos
ejecutables.
Aplique el SP2 del sqlserver pero nada
Ahora estoy reinstalando (tengo un express a mano) a ver que onda. Y lo que
estoy haciendo no es voluminoso ahora. Pero igual me da timeout, con lo cual:
O se me rompio la base ¿? o no tengo idea que puede estar pasando....
Loading...