技能创建器
skill-creator
创建、改进和评估自定义技能,把专业流程转化为可重复使用的 AI 能力。
sql-database-assistant【数据与研究】Use quando o usuário pede para escrever queries SQL, otimizar desempenho de banco de dados, gerar migrações, explorar esquemas de banco de dados, ou trabalhar com ORMs como Prisma, Drizzle, TypeORM ou SQLAlchemy.
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
name: "sql-database-assistant" description: "Use quando o usuário pede para escrever queries SQL, otimizar desempenho de banco de dados, gerar migrações, explorar esquemas de banco de dados, ou trabalhar com ORMs como Prisma, Drizzle, TypeORM ou SQLAlchemy." agents:
O companheiro operacional para design de banco de dados. Enquanto database-designer foca na arquitetura de esquemas e database-schema-designer lida com modelagem ERD, esta skill cobre o dia a dia: escrever queries, otimizar desempenho, gerar migrações e fazer a ponte entre o código da aplicação e os motores de banco de dados.
| Script | Propósito |
|---|---|
scripts/query_optimizer.py | Análise estática de queries SQL para problemas de desempenho |
scripts/migration_generator.py | Gerar templates de arquivos de migração a partir de descrições de mudanças |
scripts/schema_explorer.py | Gerar documentação de esquema a partir de queries de introspecção |
Ao converter requisitos para SQL, siga esta sequência:
Top-N por grupo (função de janela)
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rn
FROM employees
) ranked WHERE rn <= 3;
Totais acumulados
SELECT date, amount,
SUM(amount) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total
FROM transactions;
Detecção de lacunas
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);
Consulte references/query_patterns.md para JOINs, CTEs, funções de janela, operações JSON e muito mais.
PostgreSQL — listar tabelas e colunas
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 — chaves estrangeiras
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 — tamanhos de tabela
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 — dump de esquema
SELECT name, sql FROM sqlite_master WHERE type = 'table' ORDER BY name;
SQL Server — colunas com tipos
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;
Use scripts/schema_explorer.py para produzir documentação em markdown ou 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
WHERE status = 'active')| Anti-Padrão | Reescrita |
|---|---|
SELECT * FROM orders | SELECT id, status, total FROM orders (colunas explícitas) |
WHERE YEAR(created_at) = 2025 | WHERE created_at >= '2025-01-01' AND created_at < '2026-01-01' (sargável) |
| Subquery correlacionada no SELECT | LEFT JOIN com agregação |
NOT IN (SELECT ...) com NULLs | NOT EXISTS (SELECT 1 ...) |
UNION (dedup) quando não necessário | UNION ALL |
LIKE '%search%' | Índice de busca full-text (GIN/FULLTEXT) |
ORDER BY RAND() | Amostragem aleatória no lado da aplicação ou TABLESAMPLE |
Sintomas:
Correções:
include no Prisma, joinedload no SQLAlchemy)WHERE id IN (...)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
Consulte references/optimization_guide.md para leitura de planos EXPLAIN, tipos de índice e pooling de conexão.
Adicionar uma coluna (seguro)
-- Up
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
-- Down
ALTER TABLE users DROP COLUMN phone;
Renomear uma coluna (expand-contract)
-- Passo 1: Adicionar nova coluna
ALTER TABLE users ADD COLUMN full_name VARCHAR(255);
-- Passo 2: Preencher retroativamente
UPDATE users SET full_name = name;
-- Passo 3: Implantar app lendo ambas as colunas
-- Passo 4: Implantar app escrevendo apenas na nova coluna
-- Passo 5: Remover coluna antiga
ALTER TABLE users DROP COLUMN name;
Adicionar uma coluna NOT NULL (sequência segura)
-- Passo 1: Adicionar como nullable
ALTER TABLE orders ADD COLUMN region VARCHAR(50);
-- Passo 2: Preencher com padrão
UPDATE orders SET region = 'unknown' WHERE region IS NULL;
-- Passo 3: Adicionar restrição
ALTER TABLE orders ALTER COLUMN region SET NOT NULL;
ALTER TABLE orders ALTER COLUMN region SET DEFAULT 'unknown';
Criação de índice (não-bloqueante, PostgreSQL)
CREATE INDEX CONCURRENTLY idx_orders_status ON orders (status);
Toda migração deve ter um script down reversível. Para mudanças irreversíveis:
pg_dump das tabelas afetadaspython 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
| Funcionalidade | PostgreSQL | MySQL | SQLite | SQL Server |
|---|---|---|---|---|
| UPSERT | ON CONFLICT DO UPDATE | ON DUPLICATE KEY UPDATE | ON CONFLICT DO UPDATE | MERGE |
| Boolean | BOOLEAN nativo | TINYINT(1) | INTEGER | BIT |
| Auto-incremento | SERIAL / GENERATED | AUTO_INCREMENT | INTEGER PRIMARY KEY | IDENTITY |
| JSON | JSONB (indexado) | JSON | Text (ext) | NVARCHAR(MAX) |
| Array | ARRAY nativo | Não suportado | Não suportado | Não suportado |
| CTE (recursivo) | Suporte total | 8.0+ | 3.8.3+ | Suporte total |
| Funções de janela | Suporte total | 8.0+ | 3.25.0+ | Suporte total |
| Busca full-text | tsvector + GIN | Índice FULLTEXT | Extensão FTS5 | Catálogo full-text |
| LIMIT/OFFSET | LIMIT n OFFSET m | LIMIT n OFFSET m | LIMIT n OFFSET m | OFFSET m ROWS FETCH NEXT n ROWS ONLY |
information_schema varia entre motores'YYYY-MM-DD' funciona em todosDefinição de esquema
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
}
Migrações: npx prisma migrate dev --name add_user_email
API de Query: prisma.user.findMany({ where: { email: { contains: '@' } }, include: { posts: true } })
Escape hatch para SQL bruto: prisma.$queryRaw\SELECT * FROM users WHERE id = ${userId}``
Definição schema-first
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))
Migrações: npx drizzle-kit generate:pg depois npx drizzle-kit push:pg
Decoradores de entidade
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ unique: true })
email: string;
@OneToMany(() => Post, post => post.author)
posts: Post[];
}
Padrão de repositório: userRepo.find({ where: { email }, relations: ['posts'] })
Migrações: npx typeorm migration:generate -n AddUserEmail
Modelos declarativos
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')
Gerenciamento de sessão: Sempre use with Session() as session: como gerenciador de contexto
Migrações Alembic: alembic revision --autogenerate -m "add user email"
Consulte references/orm_patterns.md para comparações lado a lado e fluxos de trabalho de migração por ORM.
| Nível | Leitura Suja | Leitura Não-Repetível | Leitura Fantasma | Caso de Uso |
|---|---|---|---|---|
| READ UNCOMMITTED | Sim | Sim | Sim | Nunca recomendado |
| READ COMMITTED | Não | Sim | Sim | Padrão para PostgreSQL, OLTP geral |
| REPEATABLE READ | Não | Não | Sim (InnoDB: Não) | Cálculos financeiros |
| SERIALIZABLE | Não | Não | Não | Consistência crítica (faturamento, estoque) |
pg_advisory_lock() para coordenação no nível da aplicação# Backup completo
pg_dump -Fc --no-owner dbname > backup.dump
# Restauração
pg_restore -d dbname --clean --no-owner backup.dump
# Recuperação ponto-no-tempo: configurar arquivamento WAL + restore_command
# Backup completo
mysqldump --single-transaction --routines --triggers dbname > backup.sql
# Restauração
mysql dbname < backup.sql
# Log binário para PITR: mysqlbinlog --start-datetime="2025-01-01 00:00:00" binlog.000001
# Backup (seguro com leituras concorrentes)
sqlite3 dbname ".backup backup.db"
| Anti-Padrão | Problema | Correção |
|---|---|---|
SELECT * | Transfere dados desnecessários, quebra em mudanças de esquema | Lista explícita de colunas |
| Índices ausentes em colunas FK | JOINs lentos e exclusões em cascata | Adicionar índices em todas as chaves estrangeiras |
| Queries N+1 | 1 + N round trips para o banco de dados | Carregamento eager ou queries em lote |
| Coerção de tipo implícita | WHERE id = '123' impede uso de índice | Corresponder tipos em predicados |
| Sem pooling de conexão | Esgota conexões sob carga | PgBouncer, ProxySQL ou pool do ORM |
| Queries ilimitadas | Sem LIMIT arrrisca retornar milhões de linhas | Sempre paginar |
| Armazenar dinheiro como FLOAT | Erros de arredondamento | Usar DECIMAL(19,4) ou centavos como inteiro |
| Tabelas deus | Uma tabela com 50+ colunas | Normalizar ou usar particionamento vertical |
| Soft deletes em todo lugar | Complica toda query com WHERE deleted_at IS NULL | Tabelas de arquivo ou event sourcing |
| Concatenação de string bruta | SQL injection | Sempre usar queries parametrizadas |
| Skill | Relacionamento |
|---|---|
| database-designer | Arquitetura de esquema, análise de normalização, geração ERD |
| database-schema-designer | Modelagem visual ERD, mapeamento de relacionamentos |
| migration-architect | Orquestração de migração complexa em múltiplos passos |
| api-design-reviewer | Garantir que endpoints de API se alinhem com padrões de query |
| observability-designer | Monitoramento de desempenho de queries, alertas de query lenta |