donatello
donatello

Reputation: 6235

Is it possible to issue a "VACUUM ANALYZE <tablename>" from psycopg2 or sqlalchemy for PostgreSQL?

My db activity is very update intensive, and I want to programmatically issue a Vacuum Analyze.

However, I get an error that says that the query cannot be executed within a transaction.

Is there some other way to do it?

Upvotes: 12

Views: 7758

Answers (3)

klamann
klamann

Reputation: 1817

Not sure about older versions of SQLAlchemy, but with a recent version (1.4.x or higher) you can create an autocommit session, without handling raw connections or relying on database specific hacks:

import sqlalchemy
from sqlalchemy.orm import Session

engine = sqlalchemy.create_engine('postgresql://localhost:5432')
autocommit_engine = engine.execution_options(isolation_level="AUTOCOMMIT")
with Session(autocommit_engine) as session:
    session.execute(f'VACUUM ANALYZE public.my_table;')

The autocommit engine can be derived from any Engine object. The old Engine instance remains functional.

Upvotes: 2

Glenn Maynard
Glenn Maynard

Reputation: 57494

This is a flaw in the Python DB-API: it starts a transaction for you. It shouldn't do that; whether and when to start a transaction should be up to the programmer. Low-level, core APIs like this shouldn't babysit the developer and do things like starting transactions behind our backs. We're big boys--we can start transactions ourself, thanks.

With psycopg2, you can disable this unfortunate behavior with an API extension: run connection.autocommit = True. There's no standard API for this, unfortunately, so you have to depend on nonstandard extensions to issue commands that must be executed outside of a transaction.

No language is without its warts, and this is one of Python's. I've been bitten by this before too.

Upvotes: 16

mdh
mdh

Reputation: 5563

You can turn on Postgres autocommit mode using SQLAlchemy's raw_connection (which will give you a "raw" psycopg2 connection):

import sqlalchemy
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT


engine = sqlalchemy.create_engine(url)
connection = engine.raw_connection()
connection.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
cursor = connection.cursor()
cursor.execute("VACUUM ANALYSE table_name")

Upvotes: 14

Related Questions