Método simple de Python que lleva una eternidad ejecutar / ejecutar

8

Mi código se atasca en el clean_up()método enMyClass()

my_class.py:

import os
import pandas as pd
import psycopg2, pymysql, pyodbc
from db_credentials_dict import db_credentials

class MyClass():

    def __init__(self, from_database, to_table_name, report_name):
        ...

    def get_sql(self):
        ...

    def get_connection(self):
        ...

    def query_to_csv(self):
        ...

    def csv_to_postgres(self):
        ...

    def extract_and_load(self):
        self.query_to_csv()
        self.csv_to_postgres()

    def get_final_sql(self):
        ...

    def postgres_to_csv(self):
        ...

    def clean_up(self):
        print('\nTruncating {}...'.format(self.to_table_name), end='')
        with self.postgres_connection.cursor() as cursor:
            cursor.execute("SELECT NOT EXISTS (SELECT 1 FROM %s)" % self.to_table_name)
            empty = cursor.fetchone()[0]
            if not empty:
                cursor.execute("TRUNCATE TABLE %s" % self.to_table_name)
        self.postgres_connection.commit()
        print('DONE')

        print('Removing {}...'.format(self.filename), end='')
        if os.path.exists(self.filepath):
            os.remove(self.filepath)
            print('DONE')
        else:
            print('{} does not exist'.format(self.filename))

main.py:

from my_class import MyClass
from time import sleep

bookings = MyClass(from_database='...',to_table_name='...',report_name='...')
bookings2 = MyClass(from_database='...',to_table_name='...',report_name='...')
channel = MyClass(from_database='...',to_table_name='...',report_name='...')
cost = MyClass(from_database='...',to_table_name='...',report_name='...')

tables = [bookings, bookings2, channel, cost]
for table in tables:
    table.extract_and_load()

daily_report = MyClass(from_database='...',to_table_name='...',report_name='...')
daily_report.postgres_to_csv()
sleep(10)

for table in tables:
    table.clean_up()

Cuando ejecuto main.pyejecuta todo hasta el ciclo final, es decir for table in tables: table.clean_up(). Simplemente se queda atascado allí, sin errores ni advertencias.

Cuando ejecuta ese método por sí solo, funciona bien, es decir, trunca las tablas de postgres. Necesita ayuda para que esto funcione y comprender por qué el método final no se ejecuta cuando se ejecutan todos los demás.

Salida de cuando se ejecuta clean_up()por sí solo:

Truncating bookings...DONE
Removing bookings.csv...DONE

Truncating bookings2...DONE
Removing bookings2.csv...DONE

Truncating channel...DONE
Removing channel.csv...DONE

Truncating cost...DONE
Removing cost.csv...DONE

Lo que hace el código general:

  1. Capturar archivos que contienen consultas sql extrayendo datos de diferentes bases de datos y ejecutando esas consultas.
  2. Exportándolos a csv
  3. Importar csv a una base de datos postgres
  4. Escribir una consulta postgres que reúna datos y luego los exporte como un csv para usar en una herramienta de BI para la visualización de datos
  5. Truncar los datos en postgres y eliminar los archivos csv en el punto 2

Probablemente estés pensando que esto es una locura y estoy de acuerdo. Actualmente estoy cumpliendo con lo que tengo y no puedo almacenar datos en mi computadora porque son datos de la compañía (de ahí el truncamiento y la eliminación de los datos).

AK91
fuente
2
No puedo ver nada que cause este problema en lo que publicaste de tu código Python, por lo que el problema es muy probablemente con postgres.
bruno desthuilliers
¿Puedes publicar la salida de tu método clean_up () cuando ejecutas el suyo?
Kederrac

Respuestas:

5

TRUNCATELa cláusula en Postgres requiere un ACCESS EXCLUSIVEbloqueo en la relación y también puede activar algunos BEFORE TRUNCATEdesencadenantes.

Supongo que el problema está en el lado de Postgres, por ejemplo, TRUNCATEintenta adquirir un ACCESS EXCLUSIVEbloqueo en la relación, pero ya está bloqueado por otra persona.

Primero, verifique sus registros de Postgres.

A continuación, verifique qué están haciendo sus backends de Postgres durante su ahorcado TRUNCATEcon:

SELECT * FROM pg_stat_activity;

A continuación, investigue las cerraduras con:

-- View with readable locks info and filtered out locks on system tables
CREATE VIEW active_locks AS
SELECT clock_timestamp(), pg_class.relname, pg_locks.locktype, pg_locks.database,
       pg_locks.relation, pg_locks.page, pg_locks.tuple, pg_locks.virtualtransaction,
       pg_locks.pid, pg_locks.mode, pg_locks.granted
FROM pg_locks JOIN pg_class ON pg_locks.relation = pg_class.oid
WHERE relname !~ '^pg_' and relname <> 'active_locks';

-- Now when we want to see locks just type
SELECT * FROM active_locks;
ololobus
fuente
Gracias por esto.
Creé
OK, ¿qué pasa con pg_stat_activity? ¿Qué otros backends están haciendo? Por ejemplo, conSELECT * FROM pg_stat_activity WHERE backend_type = 'client backend' AND datname IS NOT NULL;
ololobus
2

Te sugiero que hagas el proceso de limpieza deseado en una sola transacción. Para prevenir estados no deseados.

Y verifique si la tabla existe en la base de datos utilizando el esquema de información

SELECT EXISTS (
   SELECT 1
   FROM   information_schema.tables 
   WHERE  table_schema = 'schema_name'
   AND    table_name = 'table_name'
   );

Marque Si existe, cree sus comandos truncados.

y ejecuta el proceso de limpieza todo en una transacción.

Frederic
fuente