← Torna al blog
·8 min di lettura·

Python e Postgres: smettetela di tirare la tabella in memoria

L’SQL può essere giusto e l’API muore lo stesso: .all() senza limite, query in f-string, N+1 dell’ORM, una connessione nuova per richiesta, pandas come warehouse sul box web. Come tengo Python sottile intorno a Postgres nel 2026.

PythonPostgreSQLFastAPISQLPerformanceIngegneria

L’articolo SQL è la query. Questo è il Python che rifiuta di disfarla. Rivedo lo stesso incidente: una route FastAPI pulita, un modello SQLAlchemy pulito e 200 MB di working set perché scalars().all() voleva dire «tutti». Il database ha fatto il suo. L’app ha chiesto un CSV del magazzino.

Ho già scritto le cinque forme SQL che uso al posto di un loop. Qui c’è la busta: parametri, un pool, un timeout e la disciplina di non raccogliere una tabella perché l’API del dataframe è comoda.

1. Lo script che funzionava su 800 righe

Dump locale, pandas, un groupby, un to_excel. Poi qualcuno lo punta sulla produzione «solo per questo report». Non è un report. È un estratto del database primario in un processo che l’OOM ucciderà. Se la risposta è un numero, una lista di cinquanta righe o un file che potete streammare, non raccogliete la tabella. Scrivo l’aggregazione in SQL — o una vista materializzata se è quotidiana — e tengo Python come busta: auth, parametri, formato.

2. Le f-string non sono un’API di query

Costruire SELECT * FROM orders WHERE id = {order_id} con una f-string è regalare il database. Usate $1, %(id)s o parametri bound. Ogni driver li ha. SQLAlchemy text() anche. Un LLM che concatena SQL è lo stesso bug con maniere migliori. Stessa famiglia: liste IN unendo stringhe. Usate ANY($1::int[]) o un bind vero. Non «esco» da questo con l’escape.

3. L’N+1 dell’ORM che sembra Python pulito

for invoice in invoices: invoice.customer.name è una query in più per riga. selectinload, un join, o una query di lista dedicata. «Aggiungo un loader dopo» è come muore la pagina lista dopo una fiera. Uso un ORM per le scritture che stanno all’unità di lavoro: crea ordine e righe in una sessione. SQL per liste ed export. L’ibrido non è un fallimento. Un ORM che nasconde quattrocento query sì.

4. Una connessione per richiesta non è un pool

Aprire psycopg in ogni handler, o creare un engine dentro la funzione, è come picchiate max_connections durante un deploy. Un engine o un pool async per processo. Timeout sull’acquire. Un checkout che non può vivere attraverso un await verso un altro servizio. asyncpg o psycopg 3 sul percorso caldo che controllo. SQLAlchemy se il team pensa già in sessioni e mi servono migrazioni più identity map. Non parto con tre ORM perché un tutorial usava Django.

5. Pandas è un secondo database — trattatelo così

Un groupby pandas su un frame da due gigabyte è una query di warehouse su un box API. Se vi serve pandas, l’estratto deve già essere stretto: le colonne che usate, il giorno che vi serve, un COPY o un cursore lato server. chunksize esiste. fetchmany esiste. yield esiste. pandas mi piace nei notebook di analisi. Non mi piace come implementazione di /stats. Quella route è SQL più un dict tipizzato.

6. Cosa consegno davvero

Un router FastAPI. Parametri validati — date, id dello spazio, un limite. Una funzione che esegue una query parametrizzata, spesso le forme finestra dell’altro articolo. Un pool. Uno statement timeout così un piano cattivo fa fallire la richiesta, non l’istanza. Niente SELECT *. Niente .all() silenzioso su una tabella senza limite. Una richiesta, una transazione, salvo una ragione con nome — outbox, un passaggio di pagamento. L’isolamento resta READ COMMITTED finché non so nominare l’anomalia che temo.

Conclusione: la colla sì, un secondo warehouse no

Python è la colla migliore che ho per HTTP e i job. Diventa caro quando finge di essere Postgres. Scrivete la query, bindate i parametri, streammate o aggregate, e tenete il processo piccolo. Il loop furbo può aspettare. Il database ne aveva già uno migliore — è l’altro articolo.

Parliamo del tuo progetto?

Sono un’ingegnera web senior, specializzata in React e Next.js - disponibile per progetti freelance in tutto il mondo.

Dove sono

Kyiv, Ucraina

Telegram

Contattami

WhatsApp

Contattami