2011-02-23 14 views
5

Estoy rellenando una tabla PostgreSQL con ~ 11.000.000 filas que se han seleccionado anteriormente desde otra base de datos. Estoy usando Python y psycopg2. El proceso completo demora aproximadamente 1,5 horas en completarse. Sin embargo, después de ~ 30 minutos obtengo la excepción de "conexión cerrada inesperadamente". El código fuente es el siguiente:La conexión PostgreSQL se cierra inesperadamente al hacer una inserción grande

incursor = indb.cursor() 
incursor.execute("SELECT ...") 
indb.commit() # (1) close transaction 
outcursor = outdb.cursor() 
rows = 0 
for (col1, col2, col3) in incursor: # incursor contains ~11.000.000 rows 
    outcursor.execute("INSERT ...", (col1, col2, col3)) # This fails after ~30 minutes 
    row += 1 
    if row % 100 == 0: # (2) Write data every 100 rows 
     outcursor.close() 
     outdb.commit() 
     outcursor = outdb.cursor() 
incursor.close() 
outcursor.close() 
outdb.commit() 

que inserta (1) y (2) después de los primeros intentos que fracasaron, en el supuesto de que una transacción abierta tiene un límite de tiempo superior de ~ 30 minutos o que un cursor tiene un límite superior de la espera inserciones. Parece que ninguna de estas suposiciones es verdadera y el error está en otra parte.

Ambas bases de datos se almacenan en una máquina VirtualBox que conecto mediante el reenvío de puertos desde el host. Ejecuto el programa en la máquina host.

Ambas bases de datos son solo para fines de prueba y no tienen otras conexiones que administrar. Tal vez tenga que volver a escribir el problema para evitar esto, pero necesito inserciones que consumen mucho tiempo en otros lugares (se ejecutan aproximadamente durante días), así que estoy muy preocupado por algunos límites de tiempo ocultos en psycopg2 o PostgreSQL.

+1

Creo que el problema podría estar en la variable work_mem en la configuración. AFAIK esta variable establece la memoria máxima permitida para una conexión. Compruebe los registros que debería haber una entrada acerca de cuál es incorrecto – Voooza

+0

Pero entonces la instrucción SELECT no funcionaría del todo, ¿no? Pero pierdo la conexión a 'outdb'. – WolfgangA

+0

Utilice 'COPY' o transacciones más grandes. Ejecutar solo 100 registros en una sola transacción, le da alrededor de 110.000 transacciones para completar todo el trabajo. Una sola unidad de 7400rpm solo puede manejar 120 confirmaciones por segundo (a menos que se deba a caché, eso lo haría poco confiable). Su problema actual suena como un problema de red. –

Respuesta

4

No conozco ningún tiempo de espera "oculto" en postgresql. PostgreSQL tiene statement_timeout, pero si acierta obtendrá un ERROR: canceling statement due to statement timeout en el registro del servidor (y también registrará la declaración cancelada). No puedo hablar por psycopg2. Definitivamente, revise el registro del servidor para ver si tiene algún aspecto relevante.

Quizás es un problema de red? Una declaración de larga ejecución será una conexión TCP que permanece inactiva durante mucho tiempo. ¿Tal vez su reenvío de puertos purga las conexiones que están inactivas durante más de 30 minutos? Quizás sus conexiones TCP no estén usando keepalive. Postgresql tiene algunos ajustes para ajustar TCP keepalive (tcp_keepalives_interval, etc.) y es posible que también necesite hacer alguna configuración de núcleo/red para asegurarse de que estén realmente habilitados.

p. Ej. Acabo de intentar conectarme a mi propia máquina aquí y el tcp_keepalives_interval tiene un valor predeterminado de 7200, que es de 2 horas. Si el reenvío de puertos se interrumpe después de 30 minutos, este valor predeterminado no funcionará. Puede anular la configuración utilizada en la cadena de conexión del cliente (suponiendo que pueda twiddle la cadena conninfo directamente), o establecer la variable GUC en propiedades de usuario/base de datos o postgresql.conf.

Ver:

+0

¡Muchas gracias por sus enlaces! – WolfgangA

0

Para insertar Millones de filas, me vería a través de la guide oficial a poblar una base de datos y considere usar copy.

0

Tengo un comando django admin que actualiza miles de miles de filas. Después de un tiempo, veo el mismo error. Creo que el uso de memoria excede el límite. Sin embargo, no sé cómo controlar manualmente la transacción en los comandos.

Cuestiones relacionadas