Realizar una inserccion a tabla en postgreSQL desde un cursor

508 views
Skip to first unread message

MVilchez

unread,
Feb 5, 2015, 10:06:35 AM2/5/15
to publice...@googlegroups.com
Estimados amigos,

tengan buen día, los molesto para que me den una mano.

Tengo un problema al realizar una inserción en una tabla en postgreSQL.
les explico un poco:
* Tengo una tabla *.dbf con ciertos campos y mas de 200,000 registros
* Creo un cursos donde cargo la información de la tabla, aquí es donde realizo modificaciones y validaciones a los datos de la tabla dbf
* Antes de realizar la inserción a la tabla de postgreSQL, verifico si existe un registro anteriormente cargado, SI EXISTE elimino el registro en postgreSQL.
* luego solo inserto en postgreSQL los datos de mi cursor.

hasta aquí todo bien, el problema es la lentitud se demora mas de 8 horas al realizar la carga de estos datos, mi pregunta es: Se podrá mejorar el tiempo de inserción a la base de datos?

algo como:

insert into exportacion (id, cadu, fano, ndcl, fnum, femb, etc)
select (id, cadu, fano, ndcl, fnum, femb, etc) micursor
Copio fragmento del código empleado.

*****************************************************************************************************************************************************

** Creo un Cursor 'datos' donde voy a almacenar la información trabajada de mi tabla dbf
** Selecciono mi tabla 'table' me ubico al inicio e inicio el recorrido, verificando algunos campos e insertando en mi cursor datos
 
sele table 
go top

SCAN
i=i+1
select datos
appen blank
replace campo1 with datos.campo1
...
...
...

ENDSCAN 


** selecciono el cursos con los datos listos para insertar al postgres
SELECT datos 
GO TOP 
SCAN 
lsId = ALLTRIM(id)
** Antes hago una consulta en la tabla de postgres
** busco si el archivo existe, si existe elimino
IF f_get_data_select("select count(*)::integer as dato from exportacion where id='&lsId'") > 0 THEN
sqlDel = "delete from exportacion where id='&lsId';"
EjectSQL(sqlDel)
ENDIF 

** Inserto en mi tabla de postgres los datos antes cargados en el cursor
TEXT TO sqlInsert NOSHOW TEXTMERGE
insert into exportacion (id, cadu, fano, ndcl, fnum, femb, etc)
values('<<lsid>>', '<<lscadu>>', '<<lsfano>>', '<<lsndcl>>', '<<dfnum>>', '<<dfemb>>', 'etc');
ENDTEXT

EjectSQL(sqlInsert)

ENDSCAN 



Patricio Muñoz

unread,
Feb 5, 2015, 10:22:55 AM2/5/15
to publice...@googlegroups.com
Hola

Yo creo que el problema no esta en la insercion, sino en el select y en el delete, has realizado la misma consulta desde el manager del postgres para ver su velocidad?... pienso que debe ser un problema de indice.

Por otro lado no entiendo eso del "::integer" porque lo haces?.... se supone que el count() te entrega como resultado un integer. Yo he trabajado con postgres y esa misma consulta la hago de esta manera:

"select count(*) as dato from exportacion where id=?lsId"

el signo que coloco "?" es para indicarle al odbc que esa reemplace la variable por su valor. Ademas le quito las comillas simples, solo envio la variable.

Otra cosa que hago diferente es la insercion, lo hago de la siguiente forma:

TEXT TO sqlInsert NOSHOW TEXTMERGE
insert into exportacion (id, cadu, fano, ndcl, fnum, femb, etc)
values(?lsid, ?lscadu, ?lsfano, ?lsndcl, ?dfnum, ?dfemb, ?etc);
ENDTEXT

Bendiciones
--
Patricio Muñoz
Pro&Tech
Analista en Sistemas

Miguel Canchas

unread,
Feb 5, 2015, 10:27:59 AM2/5/15
to publice...@googlegroups.com

Primero carga toda la tabla dbf en una tabla(X1) de postgres sin restricciones, luego haces las validaciones al pasar a la tabla (de postgres) que necesitas la información de la tabla X1 (de postgres)

 

 

MK

Víctor Hugo Espínola Domínguez

unread,
Feb 5, 2015, 6:38:01 PM2/5/15
to publice...@googlegroups.com
Hola MVilchez

Es probable que sea más rápido el siguiente algoritmo:

SCAN
          Enviar el comando UPDATE
          Si no hubo éxito
                 Enviar el comando INSERT
          Fin si
ENDSCAN

Saludos,
Víctor.
Lambaré - Paraguay.

mpulla

unread,
Feb 5, 2015, 6:40:12 PM2/5/15
to publice...@googlegroups.com

Hola MVilchez.

Como ya te dijo Extremo, puede ser problema de índices.

Pero en todo caso estás haciendo 2 a 3 envíos al servidor por registro, en mi caso haría una función para que elimine e inserte.

Hago así

Delete from mitabla where id = miid

Insert Into mitabla
Values
(miid)

No conozco mucho de PostgreSql, pero tienes que tener cuidado con la desfragmentación de índices.

También puedes plantearte trabajar en una tabla auxiliar en PostgreSql y cuando esté listo haces update entre las 2 tablas que es mucho mejor y vas a ver que pasas de minutos a un par de segundos.


Saludos.
Mauricio

David Salazar

unread,
Feb 5, 2015, 7:02:07 PM2/5/15
to publice...@googlegroups.com
En una ocasión tuve ese problema que tardaba demasiado tiempo en insertar datos a una tabla de postgress desde una dbf. La mejor solucion que se me ocurrio en ese momento fue trabajar con cursor adapter, y solo hice el select como tu lo mencionas

insert into exportacion (id, cadu, fano, ndcl, fnum, femb, etc)
select (id, cadu, fano, ndcl, fnum, femb, etc) from micursor

y sin tanto problema tardo como 10 segundos

Alfonso Arias Lemas

unread,
Feb 6, 2015, 5:52:30 AM2/6/15
to publice...@googlegroups.com

Hola MVilchez.

Esos problemas que tienes no tienen nada que ver con PostgreSQL y si con la configuración que usas o el escenario que tienes montado, este es un SGBD bastante maduro que ha superado todo eso y para garantizar lo que dices debes considerar varios factores tales como:

·         Están indexadas correctamente las tablas por todos los campos que realizar búsqueda o todos los campos que mantienes llaves extranjeras o foráneas (relaciones)?

·         Cuando hablamos de procesamiento de tantos registros juntos lo recomendable es trabajar en el servidor con una función o procedimiento almacenado en Postgres, ni siquiera colocar la aplicación en el servidor, la transferencia de tal volumen entre el sistema App y el servidor es un proceso muy costoso y puede ralentizar el proceso por el uso de memoria que hace. Recuerda que cada petición al servidor PostgreSqL por defecto es considerada una transacción con los costes adicionales que lleva si se incrementa el número de registros procesados proporcional será el consumo de recursos utilizados ya sea de disco rígido o memoria. Una vez cerrada la transacción todos los recursos se liberaran.

·         Otro punto, velocidad de la rede o la carga a que está sometida. El hecho de realizar la petición y procesamiento on-line de este volumen de registro es complejo también puede ser lento.

 

 

Usar 200,000 registros para PostgreSQL es como pestañar ten la certeza de eso. Yo uso tablas de millones y eso no es questionable…

 

Saudos,

    Alfonso

Reply all
Reply to author
Forward
0 new messages