Otimizando Inserções em Massa com SQLAlchemy

Em aplicações que demandam a persistência de grandes volumes de registros em um curto espaço de tempo, a utilização de operações padrão do ORM pode comprometer a performance da API. Para garantir tempos de resposta adequados, é essencial adotar estratégias de inserção em lote. Os benchmarks apresentados consideram um conjunto de dados de aproximadamente 16.000 registros.

Método 1: Inserção via ORM Convencional

Nesta abordagem, cada objeto é instanciado e adicionado à sessão individualmente. Este é o método mais lento devido ao overhead de rastreamento de mudanças do Unit of Work.


@staticmethod
def process_batch_insert(payload_list, db_session=None):
    try:
        session = db_session if db_session else global_db_session
        for item in payload_list:
            record = EntryRecord(**item)
            session.add(record)
        session.commit()
        return True
    except Exception as e:
        logger.error(f'Erro em {__name__}: {str(e)}', exc_info=True)
        session.rollback()
        return False

Método 2: Bulk Save Objects

Utiliza o método bulk_save_objects para bypassar parte do gerenciamento de estado. Para volumes extremamente altos, recomenda-se fragmentar o procseso a cada 1.000 registros.


@staticmethod
def process_batch_insert(payload_list, db_session=None):
    try:
        session = db_session if db_session else global_db_session
        record_instances = []
        for item in payload_list:
            record_instances.append(EntryRecord(**item))
        session.bulk_save_objects(record_instances)
        session.commit()
        return True
    except Exception as e:
        logger.error(f'Falha na operação: {str(e)}', exc_info=True)
        session.rollback()
        return False

Método 3: Bulk Insert Mappings

Trabalha diretamente com dicionários de mapeamento, evitando a instanciação de objetos Python, o que reduz o consumo de memória e tempo.


@staticmethod
def process_batch_insert(payload_list, db_session=None):
    try:
        session = db_session if db_session else global_db_session
        session.bulk_insert_mappings(EntryRecord, payload_list)
        session.commit()
        return True
    except Exception as e:
        logger.error(f'Exceção capturada: {str(e)}', exc_info=True)
        session.rollback()
        return False

Método 4: SQLAlchemy Core

Utiliza a API Core para executar instruções INSERT diretamente na tabela, oferecendo geralmente a melhor performance ao ignorar completamente o ORM.


@staticmethod
def process_batch_insert(payload_list, db_session=None):
    try:
        session = db_session if db_session else global_db_session
        session.execute(
            EntryRecord.__table__.insert(),
            payload_list
        )
        session.commit()
        return True
    except Exception as e:
        logger.error(f'Erro de banco de dados: {str(e)}', exc_info=True)
        session.rollback()
        return False

Tags: SQLAlchemy Python postgresql ORM Performance-Tuning

Publicado em 9-12 17:20