вариант

sql-database-assistant

alirezarezvani/claude-skills alirezarezvani/claude-skills

Преобразуйте естественный язык в SQL-запросы, оптимизируйте производительность баз данных, создавайте миграции, изучайте схемы и работайте с ORM в PostgreSQL, MySQL, SQLite и SQL Server.

...Расширить все
1
Обновлено время 2 сентября 2026 г.

Помощник по базам данных SQL — навык уровня «POWERFUL»

Обзор

Практический помощник в проектировании баз данных. В то время как специалист по проектированию баз данных сосредоточен на архитектуре схемы, а специалист по проектированию схем баз данных занимается моделированием ERD, данная квалификация охватывает повседневные задачи: написание запросов, оптимизацию производительности, генерацию миграций и устранение разрыва между кодом приложения и движками баз данных.

Основные возможности

  • Преобразованиеестественного языка в SQL — преобразование требований в корректные и высокопроизводительные запросы
  • Исследование схемы — анализ рабочих баз данных PostgreSQL, MySQL, SQLite и SQL Server
  • Оптимизация запросов — анализ EXPLAIN, рекомендации по индексам, обнаружение N+1, шаблоны переписания
  • Генерация миграций — скрипты обновления и отката, стратегии без простоев, планы отката
  • Интеграция с ORM — шаблоны и «аварийные выходы» для Prisma, Drizzle, TypeORM и SQLAlchemy
  • Поддержка нескольких баз данных — SQL с учетом диалектов и рекомендациями по совместимости

Инструменты

Скрипт Назначение
scripts/query_optimizer.py Статический анализ SQL-запросов на наличие проблем с производительностью
scripts/migration_generator.py Генерация шаблонов файлов миграции на основе описаний изменений
scripts/schema_explorer.py Генерация документации по схеме на основе запросов интроспекции

Преобразование естественного языка в SQL

Шаблоны перевода

При преобразовании требований в SQL следуйте следующей последовательности:

  1. Определите сущности — сопоставьте существительные таблицам
  2. Определите отношения — сопоставьте глаголы операторам JOIN или подзапросам
  3. Определите фильтры — сопоставьте прилагательные/условия с условиями WHERE
  4. Определите агрегации — сопоставьте «итого», «среднее», «количество» с GROUP BY
  5. Определите порядок сортировки — сопоставьте «top», «latest», «highest» с ORDER BY + LIMIT

Распространенные шаблоны запросов

Top-N по группе (окно функции)

SELECT * FROM (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rn
  FROM employees
) ranked WHERE rn <= 3;

Накопительные суммы

SELECT date, amount,
  SUM(amount) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total
FROM transactions;

Обнаружение пробелов

SELECT curr.id, curr.seq_num, prev.seq_num AS prev_seq
FROM records curr
LEFT JOIN records prev ON prev.seq_num = curr.seq_num - 1
WHERE prev.id IS NULL AND curr.seq_num > 1;

UPSERT (PostgreSQL)

INSERT INTO settings (key, value, updated_at)
VALUES ('theme', 'dark', NOW())
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = EXCLUDED.updated_at;

UPSERT (MySQL)

INSERT INTO settings (key_name, value, updated_at)
VALUES ('theme', 'dark', NOW())
ON DUPLICATE KEY UPDATE value = VALUES(value), updated_at = VALUES(updated_at);

См. файл references/query_patterns.md для получения информации о JOIN, CTE, оконных функциях, операциях с JSON и многом другом.

Изучение схемы

Запросы на самоанализ

PostgreSQL — вывод списка таблиц и столбцов

SELECT table_name, column_name, data_type, is_nullable, column_default
FROM information_schema.columns
WHERE table_schema = 'public'
ORDER BY table_name, ordinal_position;

PostgreSQL — внешние ключи

SELECT tc.table_name, kcu.column_name,
  ccu.table_name AS foreign_table, ccu.column_name AS foreign_column
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage ccu ON tc.constraint_name = ccu.constraint_name
WHERE tc.constraint_type = 'FOREIGN KEY';

MySQL — размеры таблиц

SELECT table_name, table_rows,
  ROUND(data_length / 1024 / 1024, 2) AS data_mb,
  ROUND(index_length / 1024 / 1024, 2) AS index_mb
FROM information_schema.tables
WHERE table_schema = DATABASE()
ORDER BY data_length DESC;

SQLite — дамп схемы

SELECT name, sql FROM sqlite_master WHERE type = 'table' ORDER BY name;

SQL Server — столбцы с типами

SELECT t.name AS table_name, c.name AS column_name,
  ty.name AS data_type, c.max_length, c.is_nullable
FROM sys.columns c
JOIN sys.tables t ON c.object_id = t.object_id
JOIN sys.types ty ON c.user_type_id = ty.user_type_id
ORDER BY t.name, c.column_id;

Генерация документации на основе схемы

Используйте скрипт scripts/schema_explorer.py для создания документации в формате Markdown или JSON:

python scripts/schema_explorer.py --dialect postgres --tables all --format md
python scripts/schema_explorer.py --dialect mysql --tables users,orders --format json --json

Оптимизация запросов

Рабочий процесс анализа EXPLAIN

  1. Запустите EXPLAIN ANALYZE (PostgreSQL) или EXPLAIN FORMAT=JSON (MySQL)
  2. Определите наиболее затратный узел — последовательное сканирование (Seq Scan) больших таблиц, вложенный цикл (Nested Loop) с высокими оценками количества строк
  3. Проверьте наличие отсутствующих индексов — последовательные сканирования по отфильтрованным столбцам
  4. Ищите ошибки оценки — расхождение между запланированным и фактическим количеством строк сигнализируетоб устаревших статистических данных
  5. Оцените порядок соединений (JOIN) — убедитесь, что соединение инициируется набором результатов с наименьшим количеством строк

Контрольный список рекомендаций по индексам

  • Столбцы в условиях WHERE с высокой селективностью
  • Колонки в условиях JOIN (внешние ключи)
  • Колонки в ORDER BY в сочетании с LIMIT
  • Составные индексы, соответствующие многостолбцовым предикатам WHERE (сначала столбец с наибольшей селективностью)
  • Частичные индексы для запросов с постоянными фильтрами (например, WHERE status = 'active')
  • Покрывающие индексы, позволяющие избежать обращений к таблицам в запросах с большим объемом чтения

Шаблоны переформулировки запросов

Антишаблон Переписывание
SELECT * FROM orders SELECT id, status, total FROM orders (явно указанные столбцы)
WHERE YEAR(created_at) = 2025 WHERE created_at >= '2025-01-01' AND created_at < '2026-01-01' (поддерживает SARG)
Коррелированный подзапрос в SELECT LEFT JOIN с агрегацией
NOT IN (SELECT ...) с NULL NOT EXISTS (SELECT 1 ...)
UNION (dedup), когда это не требуется UNION ALL
LIKE '%search%' Индекс полнотекстового поиска (GIN/FULLTEXT)
ORDER BY RAND() Случайная выборка на стороне приложения или TABLESAMPLE

Обнаружение «N+1»

Симптомы:

  • Цикл приложения, выполняющий один запрос на каждую родительскую строку
  • Отложенная загрузка связанных сущностей ORM внутри цикла
  • В журнале запросов отображаются сотни одинаковых шаблонов SELECT с разными ID

Решения:

  • Использовать немедленную загрузку (include в Prisma, joinedload в SQLAlchemy)
  • Пакетные запросы с WHERE id IN (...)
  • Использовать паттерн DataLoader для резолверов GraphQL

Инструмент статического анализа

python scripts/query_optimizer.py --query "SELECT * FROM orders WHERE status = 'pending'" --dialect postgres
python scripts/query_optimizer.py --query queries.sql --dialect mysql --json

См. файл references/optimization_guide.md для ознакомления с планом EXPLAIN, типами индексов и пулом соединений.

Генерация миграций

Шаблоны миграции без простоев

Добавление столбца (безопасно)

-- Добавление
ALTER TABLE users ADD COLUMN phone VARCHAR(20);

-- Удаление
ALTER TABLE users DROP COLUMN phone;

Переименование столбца (расширение-сжатие)

-- Шаг 1: Добавление нового столбца
ALTER TABLE users ADD COLUMN full_name VARCHAR(255);
-- Шаг 2: Заполнение данных
UPDATE users SET full_name = name;
-- Шаг 3: Развертывание приложения, читающего оба столбца
-- Шаг 4: Развертывание приложения, записывающего данные только в новый столбец
-- Шаг 5: Удаление старого столбца
ALTER TABLE users DROP COLUMN name;

Добавление столбца NOT NULL (безопасная последовательность)

-- Шаг 1: Добавление столбца, допускающего значение NULL
ALTER TABLE orders ADD COLUMN region VARCHAR(50);
-- Шаг 2: Заполнение значениями по умолчанию
UPDATE orders SET region = 'unknown' WHERE region IS NULL;
-- Шаг 3: Добавление ограничения
ALTER TABLE orders ALTER COLUMN region SET NOT NULL;
ALTER TABLE orders ALTER COLUMN region SET DEFAULT 'unknown';

Создание индекса (безблокирующее, PostgreSQL)

CREATE INDEX CONCURRENTLY idx_orders_status ON orders (status);

Стратегии заполнения данных

  • Пакетные обновления — обработка блоками по 1000–10 000 строк для предотвращения конфликтов блокировок
  • Фоновые задания — асинхронное выполнение заполнения с отслеживанием хода выполнения
  • Двойная запись — запись в старые и новые столбцы в переходный период
  • Запросы проверки — проверка количества строк и целостности данных после каждого пакета

Стратегии отката

Каждая миграция должна иметь скрипт отката. Для необратимых изменений:

  1. Резервное копирование перед выполнением — создание резервной копии затронутых таблиц с помощью pg_dump
  2. Флаги функций — приложение может переключаться между чтением из старой и новой схемы
  3. Теневые таблицы — сохраняйте копию исходной таблицы на время миграции

Инструмент генерации миграций

python scripts/migration_generator.py --change "добавить булево значение email_verified в таблицу users" --dialect postgres --format sql
python scripts/migration_generator.py --change "переименовать столбец name в full_name в таблице customers" --dialect mysql --format alembic --json

Поддержка нескольких баз данных

Различия между диалектами

Функция PostgreSQL MySQL SQLite SQL Server
UPSERT ПРИ КОНФЛИКТЕ ОБНОВИТЬ ПРИ ДУБЛИРОВАНИИ КЛЮЧА ОБНОВИТЬ ПРИ КОНФЛИКТЕ ОБНОВИТЬ СЛИТЬ
Булево Нативный BOOLEAN TINYINT(1) INTEGER BIT
Автоинкремент SERIAL / GENERATED AUTO_INCREMENT ЦЕЛОЕ ЧИСЛО ПЕРВИЧНЫЙ КЛЮЧ IDENTITY
JSON JSONB (с индексами) JSON Текст (расширенный) NVARCHAR(MAX)
Массив Нативный массив Не поддерживается Не поддерживается Не поддерживается
CTE (рекурсивный) Полная поддержка 8.0+ 3.8.3+ Полная поддержка
Функции окна Полная поддержка 8.0+ 3.25.0+ Полная поддержка
Полнотекстовый поиск tsvector + GIN ИндексFULLTEXT Расширение FTS5 Полнотекстовый каталог
LIMIT/OFFSET LIMIT n OFFSET m LIMIT n OFFSET m LIMIT n OFFSET m СМЕЩЕНИЕ m СТРОК, ПОЛУЧИТЬ ТОЛЬКО СЛЕДУЮЩИЕ n СТРОК

Советы по совместимости

  • Всегда используйте параметризованные запросы — это предотвращает SQL-инъекции во всех диалектах
  • Избегайте использования функций, специфичных для диалектов, в общем коде — оборачивайте их в адаптерный слой
  • Тестируйте миграции на целевом движкеструктура information_schema различается в разных движках
  • Используйте формат даты по стандарту ISO'YYYY-MM-DD' работает везде
  • Идентификаторы следует заключать в кавычки — используйте двойные кавычки (стандарт SQL) или обратные кавычки (MySQL)

Шаблоны ORM

Prisma

Определение схемы

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  posts     Post[]
  createdAt DateTime @default(now())
}

model Post {
  id       Int    @id @default(autoincrement())
  title    String
  author   User   @relation(fields: [authorId], references: [id])
  authorId Int
}

Миграции: npx prisma migrate dev --name add_user_email API запросов: prisma.user.findMany({ where: { email: { contains: '@' } }, include: { posts: true } }) Экранированный необработанный SQL: prisma.$queryRaw\SELECT * FROM users WHERE id = ${userId}``

Drizzle

Определение по схеме

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  email: varchar('email', { length: 255 }).notNull().unique(),
  name: text('name'),
  createdAt: timestamp('created_at').defaultNow(),
});

Конструктор запросов: db.select().from(users).where(eq(users.email, email)) Миграции: npx drizzle-kit generate:pg, затем npx drizzle-kit push:pg

TypeORM

Декораторы сущностей

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true })
  email: string;

  @OneToMany(() => Post, post => post.author)
  posts: Post[];
}

Шаблон репозитория: userRepo.find({ where: { email }, relations: ['posts'] }) Миграции: npx typeorm migration:generate -n AddUserEmail

SQLAlchemy

Декларативные модели

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    email = Column(String(255), unique=True, nullable=False)
    name = Column(String(255))
    posts = relationship('Post', back_populates='author')

Управление сессиями: всегда используйте with Session() в качестве контекстного менеджера session Миграции Alembic: alembic revision --autogenerate -m "add user email"

См. файл references/orm_patterns.md для сравнения и описания рабочих процессов миграции для каждого ORM.

Целостность данных

Стратегия ограничений

  • Первичные ключи — каждая таблица должна иметь один; предпочтительны суррогатные ключи (серийный номер/UUID)
  • Внешние ключи — обеспечивают референциальную целостность; явно определяйте поведение при удалении (ON DELETE)
  • Ограничения UNIQUE — для обеспечения уникальности на бизнес-уровне (электронная почта, слэг, ключ API)
  • Ограничения CHECK — проверка диапазонов, перечислений и бизнес-правил на уровне БД
  • NOT NULL — по умолчанию использовать NOT NULL; допускать нулевые значения только в тех случаях, когда они действительно необязательны

Уровни изоляции транзакций

Уровень «Грязное» чтение Неповторимое чтение Фантомное чтение Вариант использования
Чтение без фиксации Да Да Да Никогда не рекомендуется
ЧИТАТЬ С ФИКСАЦИЕЙ Нет Да Да По умолчанию для PostgreSQL, общие задачи OLTP
ПОВТОРИМОЕ ЧТЕНИЕ Нет Нет Да (InnoDB: нет) Финансовые вычисления
СЕРИАЛИЗУЕМОСТЬ Нет Нет Нет Критическая согласованность (выставление счетов, инвентаризация)

Предотвращение тупиковых ситуаций

  1. Последовательный порядок блокировки — всегда устанавливайте блокировки в одном и том же порядке по таблицам/строкам
  2. Короткие транзакции — минимизируйте время между установкой первой блокировки и фиксацией
  3. Консультативные блокировки — используйте pg_advisory_lock() для координации на уровне приложения
  4. Логика повторных попыток — перехват ошибок взаимной блокировки и повторная попытка с экспоненциальным отступлением

Резервное копирование и восстановление

PostgreSQL

# Полное резервное копирование
pg_dump -Fc --no-owner dbname > backup.dump
# Восстановление
pg_restore -d dbname --clean --no-owner backup.dump
# Восстановление к определенному моменту времени: настройте архивирование WAL + restore_command

MySQL

# Полное резервное копирование
mysqldump --single-transaction --routines --triggers dbname > backup.sql
# Восстановление
mysql dbname < backup.sql
# Бинарный журнал для восстановления на определенный момент времени (PITR): mysqlbinlog --start-datetime="2025-01-01 00:00:00" binlog.000001

SQLite

# Резервное копирование (безопасно при одновременном чтении)
sqlite3 dbname ".backup backup.db"

Рекомендации по резервному копированию

  • Автоматизация — cron или таймер systemd, никогда не выполняйте резервное копирование исключительно вручную
  • Тестируйте восстановление — непроверенные резервные копии не являются резервными копиями
  • Внесайтовые копии — S3, GCS или отдельный регион
  • Политика хранения — ежедневно в течение 7 дней, еженедельно в течение 4 недель, ежемесячно в течение 12 месяцев
  • Отслеживайте размер и продолжительность резервного копирования — резкие изменения сигнализируют о проблемах

Антипаттерны

Антипаттерн Проблема Решение
SELECT * Передаёт ненужные данные, вызывает сбои при изменениях схемы Явный список столбцов
Отсутствуют индексы на столбцах внешних ключей Медленные операции JOIN и каскадное удаление Добавить индексы на все внешние ключи
Запросы N+1 1 + N циклов обмена данными с базой данных Предварительная загрузка или пакетные запросы
Неявное приведение типов УсловиеWHERE id = '123' препятствует использованию индекса Соответствие типов в предикатах
Отсутствие пула соединений Исчерпывает количество соединений при высокой нагрузке PgBouncer, ProxySQL или пул ORM
Неограниченные запросы Отсутствие LIMIT создает риск возврата миллионов строк Всегда использовать пагинацию
Хранение денежных сумм в формате FLOAT Ошибки округления Используйте DECIMAL(19,4) или целые центы
«Божественные» таблицы Одна таблица с более чем 50 столбцами Нормализуйте или используйте вертикальное разбиение
«Мягкие» удаления повсеместно Усложняет каждый запрос с условием WHERE deleted_at IS NULL Архивируйте таблицы или используйте event sourcing
Конкатенация необработанных строк SQL-инъекция Всегда использовать параметризованные запросы

Перекрестные ссылки

Навык Связь
разработчик баз данных Архитектура схемы, анализ нормализации, генерация ERD
разработчик схемы базы данных Визуальное моделирование ERD, отображение связей
архитектор-миграции Организация сложных многоэтапных миграций
api-design-reviewer Обеспечение соответствия конечных точек API шаблонам запросов
observability-platform Мониторинг производительности запросов, оповещения о медленных запросах
Посмотреть на GitHub
---
name: sql-database-assistant
description: Translate natural language into SQL queries, optimize database performance, generate migrations, explore schemas, and work with ORMs across PostgreSQL, MySQL, SQLite, and SQL Server.
---

# SQL Database Assistant - POWERFUL Tier Skill

## Overview

The operational companion to database design. While **database-designer** focuses on schema architecture and **database-schema-designer** handles ERD modeling, this skill covers the day-to-day: writing queries, optimizing performance, generating migrations, and bridging the gap between application code and database engines.

### Core Capabilities

- **Natural Language to SQL** — translate requirements into correct, performant queries
- **Schema Exploration** — introspect live databases across PostgreSQL, MySQL, SQLite, SQL Server
- **Query Optimization** — EXPLAIN analysis, index recommendations, N+1 detection, rewrite patterns
- **Migration Generation** — up/down scripts, zero-downtime strategies, rollback plans
- **ORM Integration** — Prisma, Drizzle, TypeORM, SQLAlchemy patterns and escape hatches
- **Multi-Database Support** — dialect-aware SQL with compatibility guidance

### Tools

| Script | Purpose |
|--------|---------|
| `scripts/query_optimizer.py` | Static analysis of SQL queries for performance issues |
| `scripts/migration_generator.py` | Generate migration file templates from change descriptions |
| `scripts/schema_explorer.py` | Generate schema documentation from introspection queries |

---

## Natural Language to SQL

### Translation Patterns

When converting requirements to SQL, follow this sequence:

1. **Identify entities** — map nouns to tables
2. **Identify relationships** — map verbs to JOINs or subqueries
3. **Identify filters** — map adjectives/conditions to WHERE clauses
4. **Identify aggregations** — map "total", "average", "count" to GROUP BY
5. **Identify ordering** — map "top", "latest", "highest" to ORDER BY + LIMIT

### Common Query Templates

**Top-N per group (window function)**
```sql
SELECT * FROM (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rn
  FROM employees
) ranked WHERE rn <= 3;
```

**Running totals**
```sql
SELECT date, amount,
  SUM(amount) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total
FROM transactions;
```

**Gap detection**
```sql
SELECT curr.id, curr.seq_num, prev.seq_num AS prev_seq
FROM records curr
LEFT JOIN records prev ON prev.seq_num = curr.seq_num - 1
WHERE prev.id IS NULL AND curr.seq_num > 1;
```

**UPSERT (PostgreSQL)**
```sql
INSERT INTO settings (key, value, updated_at)
VALUES ('theme', 'dark', NOW())
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = EXCLUDED.updated_at;
```

**UPSERT (MySQL)**
```sql
INSERT INTO settings (key_name, value, updated_at)
VALUES ('theme', 'dark', NOW())
ON DUPLICATE KEY UPDATE value = VALUES(value), updated_at = VALUES(updated_at);
```

> See references/query_patterns.md for JOINs, CTEs, window functions, JSON operations, and more.

---

## Schema Exploration

### Introspection Queries

**PostgreSQL — list tables and columns**
```sql
SELECT table_name, column_name, data_type, is_nullable, column_default
FROM information_schema.columns
WHERE table_schema = 'public'
ORDER BY table_name, ordinal_position;
```

**PostgreSQL — foreign keys**
```sql
SELECT tc.table_name, kcu.column_name,
  ccu.table_name AS foreign_table, ccu.column_name AS foreign_column
FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage ccu ON tc.constraint_name = ccu.constraint_name
WHERE tc.constraint_type = 'FOREIGN KEY';
```

**MySQL — table sizes**
```sql
SELECT table_name, table_rows,
  ROUND(data_length / 1024 / 1024, 2) AS data_mb,
  ROUND(index_length / 1024 / 1024, 2) AS index_mb
FROM information_schema.tables
WHERE table_schema = DATABASE()
ORDER BY data_length DESC;
```

**SQLite — schema dump**
```sql
SELECT name, sql FROM sqlite_master WHERE type = 'table' ORDER BY name;
```

**SQL Server — columns with types**
```sql
SELECT t.name AS table_name, c.name AS column_name,
  ty.name AS data_type, c.max_length, c.is_nullable
FROM sys.columns c
JOIN sys.tables t ON c.object_id = t.object_id
JOIN sys.types ty ON c.user_type_id = ty.user_type_id
ORDER BY t.name, c.column_id;
```

### Generating Documentation from Schema

Use `scripts/schema_explorer.py` to produce markdown or JSON documentation:

```bash
python scripts/schema_explorer.py --dialect postgres --tables all --format md
python scripts/schema_explorer.py --dialect mysql --tables users,orders --format json --json
```

---

## Query Optimization

### EXPLAIN Analysis Workflow

1. **Run EXPLAIN ANALYZE** (PostgreSQL) or **EXPLAIN FORMAT=JSON** (MySQL)
2. **Identify the costliest node** — Seq Scan on large tables, Nested Loop with high row estimates
3. **Check for missing indexes** — sequential scans on filtered columns
4. **Look for estimation errors** — planned vs actual rows divergence signals stale statistics
5. **Evaluate JOIN order** — ensure the smallest result set drives the join

### Index Recommendation Checklist

- Columns in WHERE clauses with high selectivity
- Columns in JOIN conditions (foreign keys)
- Columns in ORDER BY when combined with LIMIT
- Composite indexes matching multi-column WHERE predicates (most selective column first)
- Partial indexes for queries with constant filters (e.g., `WHERE status = 'active'`)
- Covering indexes to avoid table lookups for read-heavy queries

### Query Rewriting Patterns

| Anti-Pattern | Rewrite |
|-------------|---------|
| `SELECT * FROM orders` | `SELECT id, status, total FROM orders` (explicit columns) |
| `WHERE YEAR(created_at) = 2025` | `WHERE created_at >= '2025-01-01' AND created_at < '2026-01-01'` (sargable) |
| Correlated subquery in SELECT | LEFT JOIN with aggregation |
| `NOT IN (SELECT ...)` with NULLs | `NOT EXISTS (SELECT 1 ...)` |
| `UNION` (dedup) when not needed | `UNION ALL` |
| `LIKE '%search%'` | Full-text search index (GIN/FULLTEXT) |
| `ORDER BY RAND()` | Application-side random sampling or `TABLESAMPLE` |

### N+1 Detection

**Symptoms:**
- Application loop that executes one query per parent row
- ORM lazy-loading related entities inside a loop
- Query log shows hundreds of identical SELECT patterns with different IDs

**Fixes:**
- Use eager loading (`include` in Prisma, `joinedload` in SQLAlchemy)
- Batch queries with `WHERE id IN (...)`
- Use DataLoader pattern for GraphQL resolvers

### Static Analysis Tool

```bash
python scripts/query_optimizer.py --query "SELECT * FROM orders WHERE status = 'pending'" --dialect postgres
python scripts/query_optimizer.py --query queries.sql --dialect mysql --json
```

> See references/optimization_guide.md for EXPLAIN plan reading, index types, and connection pooling.

---

## Migration Generation

### Zero-Downtime Migration Patterns

**Adding a column (safe)**
```sql
-- Up
ALTER TABLE users ADD COLUMN phone VARCHAR(20);

-- Down
ALTER TABLE users DROP COLUMN phone;
```

**Renaming a column (expand-contract)**
```sql
-- Step 1: Add new column
ALTER TABLE users ADD COLUMN full_name VARCHAR(255);
-- Step 2: Backfill
UPDATE users SET full_name = name;
-- Step 3: Deploy app reading both columns
-- Step 4: Deploy app writing only new column
-- Step 5: Drop old column
ALTER TABLE users DROP COLUMN name;
```

**Adding a NOT NULL column (safe sequence)**
```sql
-- Step 1: Add nullable
ALTER TABLE orders ADD COLUMN region VARCHAR(50);
-- Step 2: Backfill with default
UPDATE orders SET region = 'unknown' WHERE region IS NULL;
-- Step 3: Add constraint
ALTER TABLE orders ALTER COLUMN region SET NOT NULL;
ALTER TABLE orders ALTER COLUMN region SET DEFAULT 'unknown';
```

**Index creation (non-blocking, PostgreSQL)**
```sql
CREATE INDEX CONCURRENTLY idx_orders_status ON orders (status);
```

### Data Backfill Strategies

- **Batch updates** — process in chunks of 1000-10000 rows to avoid lock contention
- **Background jobs** — run backfills asynchronously with progress tracking
- **Dual-write** — write to old and new columns during transition period
- **Validation queries** — verify row counts and data integrity after each batch

### Rollback Strategies

Every migration must have a reversible down script. For irreversible changes:

1. **Backup before execution** — `pg_dump` the affected tables
2. **Feature flags** — application can switch between old/new schema reads
3. **Shadow tables** — keep a copy of the original table during migration window

### Migration Generator Tool

```bash
python scripts/migration_generator.py --change "add email_verified boolean to users" --dialect postgres --format sql
python scripts/migration_generator.py --change "rename column name to full_name in customers" --dialect mysql --format alembic --json
```

---

## Multi-Database Support

### Dialect Differences

| Feature | PostgreSQL | MySQL | SQLite | SQL Server |
|---------|-----------|-------|--------|------------|
| UPSERT | `ON CONFLICT DO UPDATE` | `ON DUPLICATE KEY UPDATE` | `ON CONFLICT DO UPDATE` | `MERGE` |
| Boolean | Native `BOOLEAN` | `TINYINT(1)` | `INTEGER` | `BIT` |
| Auto-increment | `SERIAL` / `GENERATED` | `AUTO_INCREMENT` | `INTEGER PRIMARY KEY` | `IDENTITY` |
| JSON | `JSONB` (indexed) | `JSON` | Text (ext) | `NVARCHAR(MAX)` |
| Array | Native `ARRAY` | Not supported | Not supported | Not supported |
| CTE (recursive) | Full support | 8.0+ | 3.8.3+ | Full support |
| Window functions | Full support | 8.0+ | 3.25.0+ | Full support |
| Full-text search | `tsvector` + GIN | `FULLTEXT` index | FTS5 extension | Full-text catalog |
| LIMIT/OFFSET | `LIMIT n OFFSET m` | `LIMIT n OFFSET m` | `LIMIT n OFFSET m` | `OFFSET m ROWS FETCH NEXT n ROWS ONLY` |

### Compatibility Tips

- **Always use parameterized queries** — prevents SQL injection across all dialects
- **Avoid dialect-specific functions in shared code** — wrap in adapter layer
- **Test migrations on target engine** — `information_schema` varies between engines
- **Use ISO date format** — `'YYYY-MM-DD'` works everywhere
- **Quote identifiers** — use double quotes (SQL standard) or backticks (MySQL)

---

## ORM Patterns

### Prisma

**Schema definition**
```prisma
model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  posts     Post[]
  createdAt DateTime @default(now())
}

model Post {
  id       Int    @id @default(autoincrement())
  title    String
  author   User   @relation(fields: [authorId], references: [id])
  authorId Int
}
```

**Migrations**: `npx prisma migrate dev --name add_user_email`
**Query API**: `prisma.user.findMany({ where: { email: { contains: '@' } }, include: { posts: true } })`
**Raw SQL escape hatch**: `prisma.$queryRaw\`SELECT * FROM users WHERE id = ${userId}\``

### Drizzle

**Schema-first definition**
```typescript
export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  email: varchar('email', { length: 255 }).notNull().unique(),
  name: text('name'),
  createdAt: timestamp('created_at').defaultNow(),
});
```

**Query builder**: `db.select().from(users).where(eq(users.email, email))`
**Migrations**: `npx drizzle-kit generate:pg` then `npx drizzle-kit push:pg`

### TypeORM

**Entity decorators**
```typescript
@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true })
  email: string;

  @OneToMany(() => Post, post => post.author)
  posts: Post[];
}
```

**Repository pattern**: `userRepo.find({ where: { email }, relations: ['posts'] })`
**Migrations**: `npx typeorm migration:generate -n AddUserEmail`

### SQLAlchemy

**Declarative models**
```python
class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    email = Column(String(255), unique=True, nullable=False)
    name = Column(String(255))
    posts = relationship('Post', back_populates='author')
```

**Session management**: Always use `with Session() as session:` context manager
**Alembic migrations**: `alembic revision --autogenerate -m "add user email"`

> See references/orm_patterns.md for side-by-side comparisons and migration workflows per ORM.

---

## Data Integrity

### Constraint Strategy

- **Primary keys** — every table must have one; prefer surrogate keys (serial/UUID)
- **Foreign keys** — enforce referential integrity; define ON DELETE behavior explicitly
- **UNIQUE constraints** — for business-level uniqueness (email, slug, API key)
- **CHECK constraints** — validate ranges, enums, and business rules at the DB level
- **NOT NULL** — default to NOT NULL; make nullable only when genuinely optional

### Transaction Isolation Levels

| Level | Dirty Read | Non-Repeatable Read | Phantom Read | Use Case |
|-------|-----------|-------------------|-------------|----------|
| READ UNCOMMITTED | Yes | Yes | Yes | Never recommended |
| READ COMMITTED | No | Yes | Yes | Default for PostgreSQL, general OLTP |
| REPEATABLE READ | No | No | Yes (InnoDB: No) | Financial calculations |
| SERIALIZABLE | No | No | No | Critical consistency (billing, inventory) |

### Deadlock Prevention

1. **Consistent lock ordering** — always acquire locks in the same table/row order
2. **Short transactions** — minimize time between first lock and commit
3. **Advisory locks** — use `pg_advisory_lock()` for application-level coordination
4. **Retry logic** — catch deadlock errors and retry with exponential backoff

---

## Backup & Restore

### PostgreSQL
```bash
# Full backup
pg_dump -Fc --no-owner dbname > backup.dump
# Restore
pg_restore -d dbname --clean --no-owner backup.dump
# Point-in-time recovery: configure WAL archiving + restore_command
```

### MySQL
```bash
# Full backup
mysqldump --single-transaction --routines --triggers dbname > backup.sql
# Restore
mysql dbname < backup.sql
# Binary log for PITR: mysqlbinlog --start-datetime="2025-01-01 00:00:00" binlog.000001
```

### SQLite
```bash
# Backup (safe with concurrent reads)
sqlite3 dbname ".backup backup.db"
```

### Backup Best Practices
- **Automate** — cron or systemd timer, never manual-only
- **Test restores** — untested backups are not backups
- **Offsite copies** — S3, GCS, or separate region
- **Retention policy** — daily for 7 days, weekly for 4 weeks, monthly for 12 months
- **Monitor backup size and duration** — sudden changes signal issues

---

## Anti-Patterns

| Anti-Pattern | Problem | Fix |
|-------------|---------|-----|
| `SELECT *` | Transfers unnecessary data, breaks on schema changes | Explicit column list |
| Missing indexes on FK columns | Slow JOINs and cascading deletes | Add indexes on all foreign keys |
| N+1 queries | 1 + N round trips to database | Eager loading or batch queries |
| Implicit type coercion | `WHERE id = '123'` prevents index use | Match types in predicates |
| No connection pooling | Exhausts connections under load | PgBouncer, ProxySQL, or ORM pool |
| Unbounded queries | No LIMIT risks returning millions of rows | Always paginate |
| Storing money as FLOAT | Rounding errors | Use `DECIMAL(19,4)` or integer cents |
| God tables | One table with 50+ columns | Normalize or use vertical partitioning |
| Soft deletes everywhere | Complicates every query with `WHERE deleted_at IS NULL` | Archive tables or event sourcing |
| Raw string concatenation | SQL injection | Parameterized queries always |

---

## Cross-References

| Skill | Relationship |
|-------|-------------|
| **database-designer** | Schema architecture, normalization analysis, ERD generation |
| **database-schema-designer** | Visual ERD modeling, relationship mapping |
| **migration-architect** | Complex multi-step migration orchestration |
| **api-design-reviewer** | Ensuring API endpoints align with query patterns |
| **observability-platform** | Query performance monitoring, slow query alerts |

Все файлы

0 файлов

Установить sql-database-assistant

Скачайте файлы навыков и распакуйте их в каталог .claude/skills/.

Скачать ZIP

Клонируйте репозиторий и скопируйте файлы навыка в свой проект.

git clone https://github.com/alirezarezvani/claude-skills/tree/main/engineering/skills/sql-database-assistant # Copy SKILL.md to your .claude/skills/ directory

Копировать Копировать
Быстрая настройка: Скопируйте папку со скиллом в каталог .claude/skills/ Claude автоматически обнаружит и запустит этот скилл
Репозиторий alirezarezvani/claude-skills

Похожие навыки

microservices-patterns
Обновлено время 29 июня 2026 г.
jpa-patterns
Обновлено время 30 июня 2026 г.
fabric-lakehouse
Обновлено время 30 июня 2026 г.
prisma-expert
Обновлено время 29 июня 2026 г.
OR