Cinci modele SQL care înlocuiesc o buclă Python – și de ce câștigă
Cel mai scump Python pe care îl revizuiesc este pentru comandă în comenzi după un SELECT *. Ultimul rând pe grup, lună peste lună, contorizările filtrate și reclamele sunt interogări. Cum le scriu în Postgres în loc să descarc tabelul.
Cel mai scump Python pe care îl revizuiesc nu este manipulatorul FastAPI netipizat. Este ordinea for în comenzi care există pentru că nimeni nu a scris o funcție de fereastră. Bucla pare sinceră. De asemenea, un raport care a durat patru secunde devine patruzeci, apoi un timeout luni după un weekend bun de vânzări.
Am scris deja cum aleg un tip de bază de date. Acesta este următorul strat: SQL-ul pe care îl scriu de fapt atunci când întrebarea despre produs este „ultima comandă per client”, „venit luna aceasta față de ultima” sau „introduceți această rezervare dacă nu este ocupat acel interval”. Postgres le poate răspunde într-o călătorie dus-întors. Python poate și – după ce a descărcat tabelul. Piesa însoțitoare este modul în care acea interogare ar trebui să părăsească Python fără a trage grămada înapoi.
1. Bucla care descarcă tabelul
Un script tipic: SELECT * FROM comenzi, apoi grupați într-un dict, apoi alegeți cel mai recent create_at per customer_id. Pe 800 de rânduri se simte bine. Pe 800.000 este un bilet de suport. Baza de date are deja indexul, sortarea și memoria pentru aceasta. Ai plătit pentru asta. Utilizarea Python ca un al doilea motor de interogare este modul în care costul apare în latență, nu pe o factură pe care ați planificat-o.
- Dacă rezultatul este mai mic decât sursa și regula are un nume – ultimul, sumă, rang, există – este o interogare.
- Dacă regula este un eseu de afaceri – rambursări cu o excepție umană, un paragraf de politică – poate rămâne în Python.
2. Ultimul rând pe grup – DISTINCT ON și ROW_NUMBER
Abonament curent per spațiu de lucru. Cea mai recentă stare a facturii per comandă. Șoferul care a dat ultimul ping. Aceasta este prima buclă pe care o șterg. În Postgres scriu DISTINCT ON (workspace_id) și ORDER BY workspace_id, created_at DESC. Vărul portabil este ROW_NUMBER() OVER (PARTIȚIE BY workspace_id ORDER BY created_at DESC), apoi păstrați rn = 1.
DISTINCT ON este mai scurt și îl folosesc când dețin Postgres. ROW_NUMBER este ceea ce scriu atunci când aceeași interogare trebuie să supraviețuiască unei mișcări sau când am nevoie de rangul 1 și rangul 2 – planul anterior, locul secund. Nu preluați fiecare abonament și reduceți în Python. Veți greși legăturile și veți aduce coloane pe care nu le redați niciodată.
3. Totaluri curente și „de luna trecută” – SUM OVER și LAG
Lună peste lună nu este o unire a unui tabel cu el însuși în interiorul unei bucle. LAG(venit) OVER (PARTITION BY workspace_id ORDER BY month) pune luna trecută pe același rând. SUM(amount) OVER (PARTITION BY customer_id ORDER BY created_at) este un sold curent. Funcțiile ferestrei păstrează granulația rândului și văd în continuare cartierul. GROUP BY se prăbușește. O buclă Python reconstruiește acel cartier într-un dict și uită fusurile orare.
Dacă aveți nevoie atât de rândul de detalii, cât și de totalul grupului, SUM(amount) OVER (PARTITION BY order_id) bate o a doua interogare și bate N+1 din ORM. Acesta este tot trucul: păstrați cerealele pe care le veți reda, calculați vecinătatea din motor.
4. Numărări condiționale – FILTER în loc de if
COUNT(*) FILTER (WHERE status = plătit) lângă COUNT(*) FILTER (WHERE status = rambursat) este o scanare. Versiunea Python este o trecere cu două contoare – până când cineva adaugă o a treia stare într-o a doua buclă, sau exportul crește și scanați de două ori. FILTER este lizibil. UN CAZ în interiorul SUM funcționează la motoarele care nu au primit FILTRE. Prefer FILTER în Postgres, deoarece intenția se află pe pagină: acest număr are un predicat.
5. Upsert în loc de select-then-insert
Cursa: citiți „este acest e-mail gratuit”, apoi introduceți. Două file, doi lucrători, o constrângere unică pe care o descoperi în producție. INSERT ... ON CONFLICT (e-mail) DO UPDATE – sau DO NOTHING – este tranzacția pe care baza de date știe deja să ruleze. Aceeași familie: UPDATE ... WHERE versiune = $versiune pentru o blocare optimistă. Dacă verificați-apoi-scrieți în Python, scrieți o bază de date mai proastă.
- Slocuri de rezervare, chei de idempotenta, „creați clientul dacă lipsește” – acestea sunt upsers, nu if-blocks.
- Un index unic face parte din produs. Fără el, ON CONFLICT este teatru.
6. Cum verific Nu am inventat o interogare mai lentă
EXPLICAȚI (ANALIZAȚI, BUFFERE) pe calea lentă. Dacă vedeți o scanare secvențială pe un tabel care a crescut, aveți nevoie de un index care să se potrivească cu partiția și ordinea – (workspace_id, created_at DESC) pentru DISTINCT ON. O funcție de fereastră nu este gratuită. Este încă mai ieftin decât expedierea grămezilor către aplicație. Dacă planul sortează două milioane de rânduri pentru un tablou de bord care arată douăzeci, adăugați o dată legată. SQL care înlocuiește o buclă poate fi totuși o buclă proastă în interiorul motorului.
Concluzie: denumește setul de rezultate, scrie interogarea
Python este un loc bun pentru HTTP, politica și propoziția pe care o arătați utilizatorului. Este un loc sărac pentru a redescoperi GROUP BY. Învățați cinci forme – ultimul pe grup, întârziere, suma curentă, agregate filtrate, upsert – și majoritatea scripturilor „inteligente” pe care le examinez devin o vizualizare sau o singură interogare într-o funcție de depozit. Celălalt articol este Python care refuză să anuleze acea lucrare.
Închiriază cu 1 clic
Angajează-mă ca dezvoltator cu un singur clic. Începeți un contract Upwork securizat pentru a construi soluții web de mare conversie pentru afacerea dvs.
Sunteți gata să discutați despre proiectul dvs.?
Sunt un inginer web senior specializat în React și Next.js - disponibil pentru proiecte independente din întreaga lume.
Locaţie
Kiev, Ucraina
Upwork
Vizualizați profilulTelegram
Contactați-măViber
Contactați-mă