Przejdź do głównej zawartości

Optymalizacja 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.

  • Konfigurację serwera MCP bazy danych tylko do odczytu dla Claude Code, Codeksa i Cursora, dzięki której agent czyta wynik EXPLAIN zamiast 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 ALL w 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:

  1. Zmierz. Zbierz plan na stagingu z danymi wielkości produkcyjnej. Tabela z 50 000 wierszy i tabela z 80 milionami dostają różne plany.
  2. 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.
  3. Zasymuluj. Przetestuj kandydata jako indeks hipotetyczny (rozszerzenie hypopg), zanim cokolwiek zbudujesz.
  4. Zmień. Zapisz jeden indeks albo jedno przepisanie jako plik migracji. Nie stosuj go z sesji agenta.
  5. Udowodnij. Dołącz do pull requesta plan „przed” i „po”, wynik zgodności dla przepisań i koszt zapisu.

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.

Okno terminala
# Terminal, repo root: writes .mcp.json; ${STAGING_DATABASE_URL} is expanded from your shell at launch
claude mcp add -s project postgres -e 'DATABASE_URI=${STAGING_DATABASE_URL}' \
-- uvx postgres-mcp --access-mode=restricted

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 bazaSerwerDlaczego
Własny lub zarządzany PostgresPostgres MCP Pro (crystaldba/postgres-mcp)explain_query z indeksami hipotetycznymi, get_top_queries, rekomendacje indeksów
MySQL, MariaDB, SQL Server, SQLite lub kilka silnikówDBHub (@bytebase/dbhub)Jeden serwer z trybem tylko do odczytu, limitem wierszy i limitem czasu zapytań
Wiele silników w jednej konfiguracjiMCP Toolbox for Databases (Google)Gotowe narzędzia dla każdego silnika albo własne narzędzia w tools.yaml
Supabase lub NeonZdalny serwer dostawcySupabase 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.

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 those
CREATE INDEX CONCURRENTLY idx_customers_active
ON customers (customer_id) WHERE status = 'active';
-- GIN: JSONB containment (@>) and full-text search
CREATE INDEX CONCURRENTLY idx_products_attributes
ON products USING gin (attributes);
-- BRIN: append-only, naturally time-ordered data; tiny on disk
CREATE 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:

Okno terminala
claude --permission-mode plan

Wklej 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ł.

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ść.

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.

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:

PotrzebujeszPostgreSQLMySQLBigQuery, Snowflake
Przybliżonej liczby unikalnych wartościBrak 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ówAPPROX_COUNT_DISTINCT(id) działa natywnie
Planu z prawdziwymi czasamiEXPLAIN (ANALYZE, BUFFERS)EXPLAIN ANALYZE (MySQL 8.0.18 i nowsze); również wykonuje zapytanieProfil zapytania danego silnika
Budowy indeksu bez blokowania zapisówCREATE INDEX CONCURRENTLYOnline DDL w InnoDB: ALGORITHM=INPLACE, LOCK=NONENie dotyczy
Testu usunięcia przed usunięciemIndeksy hipotetyczne przez hypopgUstaw 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.

ZmianaDowód, który ją potwierdzaKto zatwierdza
Nowy indeksEXPLAIN (ANALYZE, BUFFERS) przed i po ze stagingu, tabele, których zapisy spowolni, i jego rozmiarWłaściciel zapytania; tech lead dla tabel z dużym ruchem zapisów
Przepisanie zapytaniaWynik zgodności 0 dla EXCEPT ALL w obu kierunkach, zapisany jako test, oraz oba czasyWłaściciel zapytania
Poprawka N+1Test liczby zapytań w CI i dwa zapytania SQL, które wysyła kodWłaściciel zapytania
Usunięcie indeksuZero skanów od znanego resetu na każdej replice albo okres testowy z indeksem niewidocznym lub hipotetycznymTech lead
Tabela podsumowańZapytanie uzgadniające zwraca 0 wierszy po backfillu, zapisane jako test, plus nocny alert o rozjeździeTech 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.

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.

wcale bardzo