← Bloga dön
·8 dk okuma·

Python ve Postgres: tabloyu belleğe çekmeyi bırakın

SQL doğru olsa da API yine ölür: sınırsız .all(), f-string sorgular, ORM N+1, istek başına yeni bağlantı, web kutusunda depo gibi pandas. 2026’da Python’u Postgres’in çevresinde nasıl ince tutarım.

PythonPostgreSQLFastAPISQLPerformansMühendislik

SQL yazısı sorgudur. Burası onu geri almayı reddeden Python. Hep aynı kazayı görüyorum: temiz bir FastAPI rotası, temiz bir SQLAlchemy modeli ve 200 MB çalışma kümesi — çünkü scalars().all() «hepsi» demekti. Veritabanı işini yaptı. Uygulama deponun CSV’sini istedi.

Döngü yerine kullandığım beş SQL biçimini zaten yazdım. Burası zarf: parametreler, bir havuz, bir zaman aşımı ve dataframe API’si rahat diye tablo toplamama disiplini.

1. 800 satırda çalışan betik

Yerel döküm, pandas, bir groupby, bir to_excel. Sonra biri bunu üretime «sadece bu rapor için» çevirir. Bu rapor değildir. Birincil veritabanının, OOM’un öldüreceği bir sürece çıkarılmasıdır. Yanıt bir sayı, elli satırlık bir liste veya akıtabileceğiniz bir dosyaysa tabloyu toplamayın. Toplamı SQL’de yazarım — günlükse materialized view — ve Python’u zarf olarak tutarım: auth, parametreler, biçim.

2. f-string bir sorgu API’si değildir

f-string ile SELECT * FROM orders WHERE id = {order_id} kurmak, veritabanını bağışlamaktır. $1, %(id)s veya bağlı parametre kullanın. Her sürücüde vardır. SQLAlchemy text()’te de vardır. SQL birleştiren bir LLM, daha nazik halleri olan aynı hatadır. Aynı aile: dizeleri birleştirerek IN listesi. ANY($1::int[]) veya düzgün bir bind kullanın. Bundan «kaçarak» çıkmam.

3. Temiz Python gibi duran ORM N+1

for invoice in invoices: invoice.customer.name satır başına artı bir sorgudur. selectinload, bir join veya ayrı bir liste sorgusu. «Loader’ı sonra eklerim» fuardan sonra liste sayfasının ölme biçimidir. ORM’i iş birimine uyan yazmalar için kullanırım — bir oturumda sipariş artı satırlar. Liste sayfaları ve dışa aktarma için SQL. Hibrit başarısızlık değildir. Dört yüz sorguyu gizleyen bir ORM öyledir.

4. İstek başına bir bağlantı havuz değildir

Her handler’da psycopg açmak veya fonksiyonun içinde engine yaratmak, dağıtımda max_connections’a çarpma biçiminizdir. Süreç başına bir engine veya bir async havuz. Acquire’da zaman aşımı. Başka bir servisi çağıran bir await boyunca yaşamaması gereken bir checkout. Kontrol ettiğim sıcak yolda asyncpg veya psycopg 3. Ekip zaten oturumlarla düşünüyorsa ve migration artı identity map lazımsa SQLAlchemy. Bir rehber Django kullandı diye üç ORM başlatmam.

5. Pandas ikinci bir veritabanıdır — öyle davranın

İki gigabaytlık bir çerçevede pandas groupby, bir API kutusunda çalıştırdığınız bir depo sorgusudur. pandas lazımsa çıkarım zaten dar olmalı: kullandığınız sütunlar, ihtiyaç duyduğunuz gün, bir COPY veya sunucu taraflı imleç. chunksize vardır. fetchmany vardır. yield vardır. pandas’ı analiz defterlerinde severim. /stats’ın uygulaması olarak sevmem. O rota SQL artı tipli bir dict’tir.

6. Gerçekten teslim ettiğim

Bir FastAPI yönlendiricisi. Doğrulanmış parametreler — tarihler, çalışma alanı kimliği, bir limit. Çoğu zaman diğer yazıdaki pencere biçimleri olan, tek parametreli sorgu çalıştıran bir fonksiyon. Bir havuz. Kötü bir planın örneği değil isteği düşürmesi için statement timeout. SELECT * yok. Sınırsız tabloda sessiz .all() yok. Adı konmuş bir neden yoksa — outbox, bir ödeme teslimi — bir istek, bir işlem. Korktuğum anomalinin adını koyana kadar yalıtım READ COMMITTED kalır.

Sonuç: tutkal olur, ikinci depo olmaz

Python, HTTP ve işler için sahip olduğum en iyi tutkaldır. Postgres’i taklit ettiğinde pahalılaşır. Sorguyu yazın, parametreleri bağlayın, akıtın veya toplayın ve süreci küçük tutun. Zeki döngü bekleyebilir. Veritabanının zaten daha iyisi vardı — o diğer yazı.

Projenizi konuşalım mı?

React ve Next.js konusunda uzman kıdemli bir web geliştiriciyim - dünya çapında freelance projelere açığım.