Skills Plugins MCP Prompt Model 博客 我的中心

database-migrations

Buenas prácticas de migración de base de datos para cambios de esquema, migraciones de datos, rollbacks y despliegues de tiempo cero en PostgreSQL, MySQL y ORMs comunes (Prisma, Drizzle, Kysely, Django, TypeORM, golang-migrate).

DeepseekModel 官方收录技能 质量 优秀 · 90 v1.0.0

获取

https://deepseekmodel.com/api/download.php?id=affaan-m-ecc-docs-es-skills-database-migrations-skill-md&format=skill
下载 .skill 标准格式,含 system_prompt 与 model_config,导入任意 Agent 框架即可使用
.skill 文件中 system_prompt 字段的实际内容。
name database-migrations description Buenas prácticas de migración de base de datos para cambios de esquema, migraciones de datos, rollbacks y despliegues de tiempo cero en PostgreSQL, MySQL y ORMs comunes (Prisma, Drizzle, Kysely, Django, TypeORM, golang-migrate). origin ECC Patrones de Migración de Base de Datos Cambios de esquema de base de datos seguros y reversibles para sistemas de producción. Cuándo Activar Crear o alterar tablas de base de datos Agregar/eliminar columnas o índices Ejecutar migraciones de datos (backfill, transformación) Planificar cambios de esquema de tiempo cero (zero-downtime) Configurar herramientas de migración para un nuevo proyecto Principios Fundamentales Cada cambio es una migración — nunca alterar bases de datos de producción manualmente Las migraciones son solo hacia adelante en producción — los rollbacks usan nuevas migraciones hacia adelante Las migraciones de esquema y de datos son separadas — nunca mezclar DDL y DML en una migración Probar migraciones contra datos de tamaño de producción — una migración que funciona en 100 filas puede bloquear en 10M Las migraciones son inmutables una vez desplegadas — nunca editar una migración que ya se ejecutó en producción Lista de Verificación de Seguridad de Migración Antes de aplicar cualquier migración: La migración tiene tanto UP como DOWN (o está marcada explícitamente como irreversible) Sin bloqueos de tabla completa en tablas grandes (usar operaciones concurrentes) Las nuevas columnas tienen valores predeterminados o son nullable (nunca agregar NOT NULL sin valor predeterminado) Índices creados de forma concurrente (no en línea con CREATE TABLE para tablas existentes) El backfill de datos es una migración separada del cambio de esquema Probado contra una copia de datos de producción Plan de rollback documentado Patrones PostgreSQL Agregar una Columna de Forma Segura -- BIEN: Columna nullable, sin bloqueo ALTER TABLE users ADD COLUMN avatar_url TEXT; -- BIEN: Columna con valor predeterminado (Postgres 11+ es instantáneo, sin reescritura) ALTER TABLE users ADD COLUMN is_active BOOLEAN NOT NULL DEFAULT true ; -- MAL: NOT NULL sin valor predeterminado en tabla existente (requiere reescritura completa) ALTER TABLE users ADD COLUMN role TEXT NOT NULL ; -- Esto bloquea la tabla y reescribe cada fila Agregar un Índice Sin Tiempo de Inactividad -- MAL: Bloquea escrituras en tablas grandes CREATE INDEX idx_users_email ON users (email); -- BIEN: No bloqueante, permite escrituras concurrentes CREATE INDEX CONCURRENTLY idx_users_email ON users (email); -- Nota: CONCURRENTLY no puede ejecutarse dentro de un bloque de transacción -- La mayoría de herramientas de migración necesitan manejo especial para esto Renombrar una Columna (Zero-Downtime) Nunca renombrar directamente en producción. Usar el patrón expand-contract: -- Paso 1: Agregar nueva columna (migración 001) ALTER TABLE users ADD COLUMN display_name TEXT; -- Paso 2: Backfill de datos (migración 002, migración de datos) UPDATE users SET display_name = username WHERE display_name IS NULL ; -- Paso 3: Actualizar el código de la aplicación para leer/escribir ambas columnas -- Desplegar cambios de aplicación -- Paso 4: Dejar de escribir en la columna antigua, eliminarla (migración 003) ALTER TABLE users DROP COLUMN username; Eliminar una Columna de Forma Segura -- Paso 1: Eliminar todas las referencias de la aplicación a la columna -- Paso 2: Desplegar la aplicación sin la referencia a la columna -- Paso 3: Eliminar la columna en la próxima migración ALTER TABLE orders DROP COLUMN legacy_status; -- Para Django: usar SeparateDatabaseAndState para eliminar del modelo -- sin generar DROP COLUMN (luego eliminar en la próxima migración) Migraciones de Datos Grandes -- MAL: Actualiza todas las filas en una transacción (bloquea la tabla) UPDATE users SET normalized_email = LOWER (email); -- BIEN: Actualización en lotes con progreso DO $$ DECLARE batch_size INT : = 10000 ; rows_updated INT ; BEGIN LOOP UPDATE users SET normalized_email = LOWER (email) WHERE id IN ( SELECT id FROM users WHERE normalized_email IS NULL LIMIT batch_size FOR UPDATE SKIP LOCKED ); GET DIAGNOSTICS rows_updated = ROW_COUNT; RAISE NOTICE 'Updated % rows' , rows_updated; EXIT WHEN rows_updated = 0 ; COMMIT ; END LOOP; END $$; Prisma (TypeScript/Node.js) Flujo de Trabajo # Crear migración a partir de cambios de esquema npx prisma migrate dev --name add_user_avatar # Aplicar migraciones pendientes en producción npx prisma migrate deploy # Resetear base de datos (solo desarrollo) npx prisma migrate reset # Generar cliente después de cambios de esquema npx prisma generate Ejemplo de Esquema model User { id String @id @default(cuid()) email String @unique name String? avatarUrl String? @map("avatar_url") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") orders Order[] @@map("users") @@index([email]) } Migración SQL Personalizada Para operaciones que Prisma no puede expresar (índices concurrentes, backfills de datos): # Crear migración vacía, luego editar el SQL manualmente npx prisma migrate dev --create-only --name add_email_index -- migrations/20240115_add_email_index/migration.sql -- Prisma no puede generar CONCURRENTLY, por lo que se escribe manualmente CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_users_email ON users (email); Drizzle (TypeScript/Node.js) Flujo de Trabajo # Generar migración a partir de cambios de esquema npx drizzle-kit generate # Aplicar migraciones npx drizzle-kit migrate # Hacer push del esquema directamente (solo desarrollo, sin archivo de migración) npx drizzle-kit push Ejemplo de Esquema import { pgTable, text, timestamp, uuid, boolean } from "drizzle-orm/pg-core" ; export const users = pgTable ( "users" , { id : uuid ( "id" ). primaryKey (). defaultRandom (), email : text ( "email" ). notNull (). unique (), name : text ( "name" ), isActive : boolean ( "is_active" ). notNull (). default ( true ), createdAt : timestamp ( "created_at" ). notNull (). defaultNow (), updatedAt : timestamp ( "updated_at" ). notNull (). defaultNow (), }); Kysely (TypeScript/Node.js) Flujo de Trabajo (kysely-ctl) # Inicializar archivo de configuración (kysely.config.ts) kysely init # Crear un nuevo archivo de migración kysely migrate make add_user_avatar # Aplicar todas las migraciones pendientes kysely migrate latest # Revertir la última migración kysely migrate down # Mostrar estado de migraciones kysely migrate list Archivo de Migración // migrations/2024_01_15_001_create_user_profile.ts import { type Kysely , sql } from 'kysely' // IMPORTANTE: Siempre usar Kysely<any>, no tu interfaz de DB tipada. // Las migraciones están congeladas en el tiempo y no deben depender de los tipos de esquema actuales. export async function up ( db : Kysely < any > ): Promise < void > { await db. schema . createTable ( 'user_profile' ) . addColumn ( 'id' , 'serial' , ( col ) => col. primaryKey ()) . addColumn ( 'email' , 'varchar(255)' , ( col ) => col. notNull (). unique ()) . addColumn ( 'avatar_url' , 'text' ) . addColumn ( 'created_at' , 'timestamp' , ( col ) => col. defaultTo (sql `now()` ). notNull () ) . execute () await db. schema . createIndex ( 'idx_user_profile_avatar' ) . on ( 'user_profile' ) . column ( 'avatar_url' ) . execute () } export async function down ( db : Kysely < any > ): Promise < void > { await db. schema . dropTable ( 'user_profile' ). execute () } Migrador Programático import { Migrator , FileMigrationProvider } from 'kysely' import { promises as fs } from 'fs' import * as path from 'path' // Solo ESM — CJS puede usar __dirname directamente import { fileURLToPath } from 'url' const migrationFolder = path. join ( path. dirname ( fileURLToPath ( import . meta . url )), './migrations' , ) // `db` es tu instancia de base de datos Kysely<any> const migrator = new Migrator ({ db, provider : new FileMigrationProvider ({ fs, path, migrationFolder, }), // ADVERTENCIA: Solo habilitar en desarrollo. Deshabilita la validación de // ordenamiento por timestamp, lo que puede causar deriva de esquema entre entornos. // allowUnorderedMigrations: true, }) const { error, results } = await migrator. migrateToLatest () results?. forEach ( ( it ) => { if (it. status === 'Success' ) { console . log ( `migration " ${it.migrationName} " executed successfully` ) } else if (it. status === 'Error' ) { console . error ( `failed to execute migration " ${it.migrationName} "` ) } }) if (error) { console . error ( 'migration failed' , error) process. exit ( 1 ) } Django (Python) Flujo de Trabajo # Generar migración a partir de cambios de modelo python manage.py makemigrations # Aplicar migraciones python manage.py migrate # Mostrar estado de migraciones python manage.py showmigrations # Generar migración vacía para SQL personalizado python manage.py makemigrations --empty app_name -n description Migración de Datos from django.db import migrations def backfill_display_names ( apps, schema_editor ): User = apps.get_model( "accounts" , "User" ) batch_size = 5000 users = User.objects. filter (display_name= "" ) while users.exists(): batch = list (users[:batch_size]) for user in batch: user.display_name = user.username User.objects.bulk_update(batch, [ "display_name" ], batch_size=batch_size) def reverse_backfill ( apps, schema_editor ): pass # Migración de datos, no se necesita reversión class Migration (migrations.Migration): dependencies = [( "accounts" , "0015_add_display_name" )] operations = [ migrations.RunPython(backfill_display_names, reverse_backfill), ] SeparateDatabaseAndState Eliminar una columna del modelo Django sin eliminarla de la base de datos inmediatamente: class Migration (migrations.Migration): operations = [ migrations.SeparateDatabaseAndState( state_operations=[ migrations.RemoveField(model_name= "user" , name= "legacy_field" ), ], database_operations=[], # No tocar la DB todavía ), ] golang-migrate (Go) Flujo de Trabajo # Crear par de migración migrate create -ext sql - dir migrations - seq add_user_avatar # Aplicar todas las migraciones pendientes migrate -path migrations -database " $DATABASE_URL " up # Revertir la última migración migrate -path migrations -database " $DATABASE_URL " down 1 # Forzar versión (corregir estado sucio) migrate -path migrations -database " $DATABASE_URL " force VERSION Archivos de Migración -- migrations/000003_add_user_avatar.up.sql ALTER TABLE users ADD COLUMN avatar_url TEXT; CREATE INDEX CONCURRENTLY idx_users_avatar ON users (avatar_url) WHERE avatar_url IS NOT NULL ; -- migrations/000003_add_user_avatar.down.sql DROP INDEX IF EXISTS idx_users_avatar; ALTER TABLE users DROP COLUMN IF EXISTS avatar_url; Estrategia de Migración de Zero-Downtime Para cambios críticos de producción, seguir el patrón expand-contract: Fase 1: EXPAND (Expandir) - Agregar nueva columna/tabla (nullable o con valor predeterminado) - Desplegar: la app escribe en AMBAS, vieja y nueva - Backfill de datos existentes Fase 2: MIGRATE (Migrar) - Desplegar: la app lee de la NUEVA, escribe en AMBAS - Verificar consistencia de datos Fase 3: CONTRACT (Contraer) - Desplegar: la app solo usa la NUEVA - Eliminar columna/tabla antigua en migración separada Ejemplo de Línea de Tiempo Día 1: Migración agrega columna new_status (nullable) Día 1: Desplegar app v2 — escribe en status y new_status Día 2: Ejecutar migración de backfill para filas existentes Día 3: Desplegar app v3 — lee solo de new_status Día 7: Migración elimina columna status antigua Anti-Patrones Anti-Patrón Por Qué Falla Mejor Enfoque SQL manual en producción Sin historial de auditoría, no repetible Siempre usar archivos de migración Editar migraciones desplegadas Causa deriva entre entornos Crear nueva migración en su lugar NOT NULL sin valor predeterminado Bloquea tabla, reescribe todas las filas Agregar nullable, backfill, luego agregar restricción Índice en línea en tabla grande Bloquea escrituras durante la construcción CREATE INDEX CONCURRENTLY Esquema + datos en una migración Difícil de revertir, transacciones largas Migraciones separadas Eliminar columna antes de eliminar código Errores de aplicación por columna faltante Eliminar código primero, eliminar columna en el próximo despliegue
Agent 识别该技能的关键词,点击任意一个即可复制。

该技能未提供触发词。

下载的 .skill 包内含以下字段。
字段 说明
format格式标识(skill/v1)
skill_id技能唯一 ID
name技能名称
version版本号
description技能描述
category所属分类(数组)
trigger_words触发词列表
tags标签列表
source来源标识
source_url来源链接(本页地址)
exported_at导出时间(每次下载生成)
system_prompt系统提示词正文
model_config模型参数:provider / model / temperature / max_tokens / top_p
examples示例
install_guide各平台导入说明(Coze / Dify / Claude / 自定义框架)
同一份技能可按不同平台格式导出。
.skill 标准格式,含 system_prompt 与 model_config,导入任意 Agent 框架即可使用 下载
.skillpro 增强格式,额外含脚本 / 工具 / 依赖 / 钩子占位 下载
.json 纯 JSON 导出,只含 system_prompt 与模型参数 下载
Coze 带 frontmatter 的 Markdown,Coze 平台导入用 下载
Dify Dify DSL,创建应用后直接导入 下载

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

验证码 --

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。