Wzorce optymalizacji SQL
ENOptymalizacja SQL z agentem AI działa wtedy, gdy każda sugestia opiera się na dowodach z samej bazy danych. Serwer MCP tylko do odczytu pozwala Claude Code, Codeksowi lub Cursorowi czytać prawdziwy plan wykonania, statystyki tabel i użycie indeksów. Każda zmiana trafia potem do przeglądu z planem „przed” i „po”, zapytaniem zgodności zwracającym zero wierszy i podanym kosztem zapisu.
Ten przepis jest dla programisty, który odpowiada za wolne zapytanie, i dla tech leada, który zatwierdza poprawkę. Zapytanie do dashboardu, które na twoim laptopie wykonywało się w 40 ms, w produkcji przekracza limit czasu, bo tabela urosła, a planner przełączył się na skan sekwencyjny. Wklejasz SQL do agenta i dostajesz pewne siebie „dodaj indeks na customer_id”. Ten indeks już istnieje, a planner go ignoruje.
Co daje strojenie SQL oparte na planie wykonania
Dział zatytułowany „Co daje strojenie SQL oparte na planie wykonania”- Konfigurację serwera MCP bazy danych tylko do odczytu dla Claude Code, Codeksa i Cursora, dzięki której agent czyta wynik
EXPLAINzamiast zgadywać. - Prompt, który zamienia plan
EXPLAIN (ANALYZE, BUFFERS)w uszeregowane wąskie gardła i najwyżej dwa uzasadnione indeksy. - Prompt przepisujący zapytanie, który dowodzi, że nowa wersja zwraca te same wiersze, dzięki sprawdzeniu
EXCEPT ALLw obu kierunkach. - Prompt, który zwija pętlę N+1 w ORM do dwóch zapytań, oraz test liczby zapytań, który pilnuje, żeby tak zostało.
- Listę dowodów, na podstawie której recenzent zatwierdza zmianę bez czytania każdej linii SQL.
Dlaczego pierwsza propozycja indeksu od agenta chybia?
Dział zatytułowany „Dlaczego pierwsza propozycja indeksu od agenta chybia?”Agent, który widzi tylko tekst SQL, dopasowuje wzorce: indeksuje kolumny z WHERE, dokłada kilka „na wszelki wypadek” i nie odróżnia brakującego indeksu od nieaktualnych statystyk. Odpowiedź leży w planie. Plan pokazuje, który węzeł zabrał czas, jak bardzo chybiło oszacowanie liczby wierszy i czy sortowanie trafiło na dysk (spill).
Dlatego kolejność pracy jest stała:
- Zmierz. Zbierz plan na stagingu z danymi wielkości produkcyjnej. Tabela z 50 000 wierszy i tabela z 80 milionami dostają różne plany.
- Zdiagnozuj. Uszereguj węzły według rzeczywistego czasu. Sprawdź, czy oszacowanie liczby wierszy myli się dziesięciokrotnie lub bardziej. Zwykle oznacza to nieaktualne statystyki, a nie brak indeksu.
- Zasymuluj. Przetestuj kandydata jako indeks hipotetyczny (rozszerzenie
hypopg), zanim cokolwiek zbudujesz. - Zmień. Zapisz jeden indeks albo jedno przepisanie jako plik migracji. Nie stosuj go z sesji agenta.
- Udowodnij. Dołącz do pull requesta plan „przed” i „po”, wynik zgodności dla przepisań i koszt zapisu.
Podłącz serwer MCP bazy danych tylko do odczytu
Dział zatytułowany „Podłącz serwer MCP bazy danych tylko do odczytu”Serwer MCP daje agentowi bezpośredni dostęp do planu, pg_stats i pg_stat_user_indexes. Używaj bazy stagingowej albo gałęzi bazy, roli tylko do odczytu i limitu czasu zapytań. Rolę, rozszerzenia i wszystkie opcje serwerów opisuje strona serwery MCP dla baz danych. Ta strona używa Postgres MCP Pro w trybie restricted, który README dostawcy definiuje jako transakcje tylko do odczytu z limitem czasu wykonania.
# Terminal, repo root: writes .mcp.json; ${STAGING_DATABASE_URL} is expanded from your shell at launchclaude mcp add -s project postgres -e 'DATABASE_URI=${STAGING_DATABASE_URL}' \ -- uvx postgres-mcp --access-mode=restricted# ~/.codex/config.toml: env_vars forwards DATABASE_URI from your shell.# Export DATABASE_URI first, pointing at the staging read-only URL:# export DATABASE_URI="$STAGING_DATABASE_URL"[mcp_servers.postgres]command = "uvx"args = ["postgres-mcp", "--access-mode=restricted"]env_vars = ["DATABASE_URI"]Wpisz konfigurację do projektowego pliku .cursor/mcp.json. Dokumentacja MCP Cursora opisuje interpolację ${env:NAZWA}, więc plik może zawierać odwołanie do zmiennej środowiskowej zamiast sekretu. Zanim zacommitujesz plik, sprawdź w ustawieniach MCP Cursora, że serwer się łączy:
{ "mcpServers": { "postgres": { "command": "uvx", "args": ["postgres-mcp", "--access-mode=restricted"], "env": { "DATABASE_URI": "${env:STAGING_DATABASE_URL}" }} } }Postgres MCP Pro to pakiet PyPI postgres-mcp (0.3.0, ostatnie wydanie z 2025-05-16), więc uruchamiasz go przez uvx, a nie npx. Jego narzędzia do indeksów wymagają w bazie rozszerzeń pg_stat_statements i hypopg. Jeśli masz inny stos, wybierz inny serwer:
| Twoja baza | Serwer | Dlaczego |
|---|---|---|
| Własny lub zarządzany Postgres | Postgres MCP Pro (crystaldba/postgres-mcp) | explain_query z indeksami hipotetycznymi, get_top_queries, rekomendacje indeksów |
| MySQL, MariaDB, SQL Server, SQLite lub kilka silników | DBHub (@bytebase/dbhub) | Jeden serwer z trybem tylko do odczytu, limitem wierszy i limitem czasu zapytań |
| Wiele silników w jednej konfiguracji | MCP Toolbox for Databases (Google) | Gotowe narzędzia dla każdego silnika albo własne narzędzia w tools.yaml |
| Supabase lub Neon | Zdalny serwer dostawcy | Supabase przyjmuje read_only=true w adresie URL; pakiet npm Neona jest wycofany na rzecz serwera zdalnego |
Jeśli chcesz wskazówek dla Postgresa bez połączenia z bazą, Supabase publikuje skill obejmujący wydajność i row-level security: npx skills add supabase/agent-skills --skill supabase-postgres-best-practices. Skill dostarcza reguły, ale tylko serwer MCP dostarcza twój plan i statystyki, więc przy strojeniu używaj obu.
Jak dostać rekomendację indeksu z prawdziwego planu wykonania?
Dział zatytułowany „Jak dostać rekomendację indeksu z prawdziwego planu wykonania?”Najwięcej daje przekazanie agentowi prawdziwego planu i zakazanie zgadywania. Zapisy w prompcie poniżej, które każą agentowi oprzeć się na danych (sprawdź pg_stats, najpierw wypisz istniejące indeksy, najwyżej dwa nowe), odróżniają go od odpowiedzi z wyszukiwarki.
EXPLAIN ANALYZE wykonuje zapytanie. Dla SELECT na stagingu właśnie o to chodzi. Dla UPDATE, DELETE lub INSERT owiń je w BEGIN; … ROLLBACK; i nigdy nie uruchamiaj go na produkcji.
Dobierz typ indeksu do wzorca dostępu
Dział zatytułowany „Dobierz typ indeksu do wzorca dostępu”Gdy plan wskaże skan, poproś o najmniejszy indeks, który go obsłuży. Jeśli nie wymienisz alternatyw, agent wszędzie da B-tree:
-- Partial index: the hot path touches only active rows, so index only thoseCREATE INDEX CONCURRENTLY idx_customers_active ON customers (customer_id) WHERE status = 'active';
-- GIN: JSONB containment (@>) and full-text searchCREATE INDEX CONCURRENTLY idx_products_attributes ON products USING gin (attributes);
-- BRIN: append-only, naturally time-ordered data; tiny on diskCREATE INDEX CONCURRENTLY idx_events_created_at ON events USING brin (created_at);Nieużywane indeksy kosztują przy każdym zapisie. Ta sama sesja MCP je znajdzie: indeksy z idx_scan = 0 w pg_stat_user_indexes od ostatniego resetu statystyk to kandydaci do usunięcia. Zanim cokolwiek usuniesz, potwierdź datę resetu i sprawdź repliki, bo liczniki są osobne dla każdego serwera.
Poprowadź sesję strojenia w Claude Code, Codeksie i Cursorze
Dział zatytułowany „Poprowadź sesję strojenia w Claude Code, Codeksie i Cursorze”Konfiguracja MCP wygląda podobnie we wszystkich trzech narzędziach. Różnica polega na tym, jak trzymasz agenta w analizie tylko do odczytu, dopóki nie masz dowodów, a potem pozwalasz mu zapisać jeden plik migracji.
Zacznij w trybie planowania, żeby agent analizował i proponował bez edytowania plików:
claude --permission-mode planWklej prompt z planem powyżej. Gdy propozycja zawiera symulowaną zmianę planu, którą akceptujesz, wyjdź z trybu planowania klawiszami Shift+Tab (albo zaakceptuj plan, gdy Claude Code zaproponuje przejście dalej) i poproś o zapisanie pliku migracji. Claude Code pokazuje każde wywołanie narzędzia MCP, więc widzisz, jakie zapytania uruchomił.
Przeprowadź analizę z wbudowanym profilem uprawnień :read-only (beta, Codex CLI 0.138.0 lub nowszy), a potem drugie uruchomienie z profilem :workspace, żeby dostać migrację jako diff do przeglądu:
# Analysis: no file writescodex -c default_permissions=":read-only" -a on-request "Using the postgres MCP server, rank the plan nodes for the query in docs/slow-dashboard.sql and simulate at most two indexes. Do not create anything."
# Change: one migration file, reviewed as a diffcodex -c default_permissions=":workspace" -a on-request "Write the accepted index as CREATE INDEX CONCURRENTLY in a new file in db/migrations, with a matching DROP INDEX CONCURRENTLY down migration."W skrypcie codex exec -c default_permissions=":read-only" "…" wypisze analizę bez sesji interaktywnej. Starsze flagi --sandbox read-only i --sandbox workspace-write nadal działają w codex-cli 0.157.1, ale nie łączą się z profilami uprawnień, więc używaj jednego albo drugiego mechanizmu, nigdy obu naraz.
Zacznij w Plan Mode, który tworzy plan, zanim napisze jakikolwiek kod, więc analiza pozostaje tylko do odczytu. Z włączonym serwerem postgres dołącz przez @ katalog migracji i plik z wolnym zapytaniem jako kontekst i wklej prompt z planem. Gdy zaakceptujesz symulowaną zmianę planu, przełącz tryb z Plan z powrotem na Agent i poproś o zapisanie pliku migracji, a potem przejrzyj diff, zanim go zaakceptujesz.
Przepisz skorelowane podzapytanie bez zmiany wyników
Dział zatytułowany „Przepisz skorelowane podzapytanie bez zmiany wyników”Niektóre wolne zapytania mają problem z kształtem, a nie z indeksem. Klasyczny przypadek to skorelowane podzapytanie wykonywane dla każdego wiersza, a lekarstwem jest funkcja okna. Niebezpieczne nie jest samo przepisanie, tylko przepisanie, które zwraca odrobinę inne wiersze. Każ agentowi udowodnić zgodność.
Używaj EXCEPT ALL, a nie EXCEPT: zwykłe EXCEPT usuwa duplikaty, więc przepisanie, które zwraca wiersz dwukrotnie, i tak przejdzie. Zapisz zapytanie zgodności obok przepisania jako fixture testu, żeby następny refaktor też musiał je przejść.
Zwiń N+1 do dwóch zapytań
Dział zatytułowany „Zwiń N+1 do dwóch zapytań”Pętla w ORM, która dla każdego rodzica sięga po relację, wykonuje jedno zapytanie na wiersz, więc strona z 500 zamówieniami wysyła do bazy 501 zapytań. Poprawka polega na załadowaniu wszystkich dzieci jednym zapytaniem po identyfikatorach rodziców i zgrupowaniu ich w pamięci. Przykład używa Drizzle na Postgresie; Prismę i TypeORM omawia strona wzorce ORM.
Weryfikacją jest test liczby zapytań: zaświeci się na czerwono w dniu, w którym ktoś przywróci pętlę, i nikt nie musi w tym celu czytać diffu. Łapie też drugie złe przepisanie, które produkują agenci: jeden join, który przesyła każdy wiersz zamówienia tyle razy, ile ma ono pozycji.
Zdenormalizuj gorącą ścieżkę odczytu bez rozjazdu danych
Dział zatytułowany „Zdenormalizuj gorącą ścieżkę odczytu bez rozjazdu danych”Gdy join jest gorący, a jego wiersze rzadko się zmieniają, utrzymywana tabela podsumowań wygrywa z agregowaniem przy każdym żądaniu. Agenci zapominają o triggerze, który utrzymuje ją w zgodzie z danymi, a nieaktualne podsumowanie jest gorsze od wolnego zapytania. Podaj agentowi proporcję odczytów do zapisów, bo inaczej zoptymalizuje wyłącznie odczyty.
Które funkcje SQL różnią się między silnikami?
Dział zatytułowany „Które funkcje SQL różnią się między silnikami?”Agenci mieszają dialekty. Podłączony serwer MCP pozwala agentowi sprawdzić, czy funkcja istnieje, zanim ją zaproponuje, ale tylko wtedy, gdy o to poprosisz. Najczęstsze pułapki:
| Potrzebujesz | PostgreSQL | MySQL | BigQuery, Snowflake |
|---|---|---|---|
| Przybliżonej liczby unikalnych wartości | Brak wbudowanej: rozszerzenie hll (hll_cardinality(hll_add_agg(hll_hash_bigint(id)))) albo dokładne COUNT(DISTINCT …) | Brak wbudowanej: dokładne COUNT(DISTINCT …) albo tabela liczników | APPROX_COUNT_DISTINCT(id) działa natywnie |
| Planu z prawdziwymi czasami | EXPLAIN (ANALYZE, BUFFERS) | EXPLAIN ANALYZE (MySQL 8.0.18 i nowsze); również wykonuje zapytanie | Profil zapytania danego silnika |
| Budowy indeksu bez blokowania zapisów | CREATE INDEX CONCURRENTLY | Online DDL w InnoDB: ALGORITHM=INPLACE, LOCK=NONE | Nie dotyczy |
| Testu usunięcia przed usunięciem | Indeksy hipotetyczne przez hypopg | Ustaw indeks jako INVISIBLE, obserwuj, potem usuń | Nie dotyczy |
Gdy agent wymienia rozszerzenie lub funkcję, której nie znasz, na przykład wiarygodnie brzmiące pg_fastsearch, każ mu przez serwer MCP odpytać pg_available_extensions albo katalog systemowy, zanim sugestia pójdzie dalej.
Jakie dowody powinna nieść zmiana SQL do przeglądu?
Dział zatytułowany „Jakie dowody powinna nieść zmiana SQL do przeglądu?”Recenzent zatwierdza dowody, a nie prozę wokół nich. Poproś agenta, żeby zebrał je w opisie pull requesta. Sam DDL to kilka linii i nadal się go czyta, bo zmiany schematu należą do klas, w których ktoś wciąż czyta kod.
| Zmiana | Dowód, który ją potwierdza | Kto zatwierdza |
|---|---|---|
| Nowy indeks | EXPLAIN (ANALYZE, BUFFERS) przed i po ze stagingu, tabele, których zapisy spowolni, i jego rozmiar | Właściciel zapytania; tech lead dla tabel z dużym ruchem zapisów |
| Przepisanie zapytania | Wynik zgodności 0 dla EXCEPT ALL w obu kierunkach, zapisany jako test, oraz oba czasy | Właściciel zapytania |
| Poprawka N+1 | Test liczby zapytań w CI i dwa zapytania SQL, które wysyła kod | Właściciel zapytania |
| Usunięcie indeksu | Zero skanów od znanego resetu na każdej replice albo okres testowy z indeksem niewidocznym lub hipotetycznym | Tech lead |
| Tabela podsumowań | Zapytanie uzgadniające zwraca 0 wierszy po backfillu, zapisane jako test, plus nocny alert o rozjeździe | Tech lead |
Po wdrożeniu porównaj średni czas wykonania tego samego zapytania w pg_stat_statements. Wycofaniem indeksu jest DROP INDEX CONCURRENTLY, które powinno znaleźć się w migracji wycofującej (down). Bezpieczeństwo blokad samej migracji (budowa CONCURRENTLY nie może działać w bloku transakcji, a linter taki jak Squawk wyłapie zwykłą formę) opisują wzorce migracji baz danych, razem z sekwencją expand, backfill i contract dla zmiany nazwy kolumny. Ogólny format PR znajdziesz w pakiecie dowodów.
Gdy porady optymalizacyjne SQL zawodzą na produkcji
Dział zatytułowany „Gdy porady optymalizacyjne SQL zawodzą na produkcji”Dokąd dalej ze strojeniem SQL
Dział zatytułowany „Dokąd dalej ze strojeniem SQL”Cały proces pracy z bazą, od projektu schematu po wydanie, zaczyna się na stronie rozwój baz danych z agentami. Pozostałe przepisy bazodanowe zebrano w przeglądzie przepisów bazodanowych.
Czy ten artykuł Ci pomógł?
Jedno kliknięcie, bez logowania.
Co z tym zrobisz?
Jak się czytało?
Co przeszkadzało? Możesz zaznaczyć kilka
Twoja rola?
Dzięki. Czytam każdą odpowiedź. Michał Jaskólski
Pomógł Ci ten artykuł?
Każde to jedno kliknięcie. Zamknij, kiedy chcesz.
bez logowania