Escribir SQL y migraciones de base de datos con IA

Cómo escribir SQL y migraciones con agentes de IA de forma segura: da el esquema, usa un usuario de solo lectura, revisa EXPLAIN, añade índices y prueba en una copia.

Solviera Teknoloji 11 min de lectura

Para escribir SQL con IA de forma segura, dale al agente tu esquema real y un usuario de base de datos de solo lectura, haz que te muestre el plan de la consulta y mantén cada migración pequeña, reversible y probada en una copia de los datos antes de que se acerque a producción. Un agente de programación con IA escribe consultas y migraciones muy rápido. El riesgo no es que de vez en cuando escriba mal SQL, sino que una sentencia mala se ejecute donde puede hacer daño.

Esta guía cubre cómo pedir consultas, cómo comprobarlas con EXPLAIN, cómo pedir índices, cómo escribir migraciones que no bloqueen ni pierdan datos, qué papel tienen los ORM y cómo conectar un agente a una base de datos mediante MCP sin darle las llaves de producción. Los ejemplos usan PostgreSQL; las ideas sirven también para MySQL y SQLite.

Empieza por el esquema, no por la pregunta

El motivo más común de que un agente escriba una consulta errónea es que adivinó: una columna llamada user_id que en realidad es account_id, un estado guardado como entero, un indicador de borrado lógico que no conocía. Dale primero el esquema.

De dónde sacarlo:

  • Archivos de esquema del ORM. prisma/schema.prisma, tus archivos de esquema de Drizzle, models.py de Django, db/schema.rb de Rails. El agente puede leerlos directamente; menciónalos en el prompt.
  • Un volcado solo de la estructura. pg_dump --schema-only escribe las tablas, columnas, índices y restricciones sin ningún dato:
pg_dump --schema-only --no-owner "$DEV_DATABASE_URL" > schema.sql
  • Una conexión de solo lectura a la base de datos mediante un servidor MCP, para que el agente pueda listar tablas e inspeccionar columnas por su cuenta (más sobre esto abajo).

Luego añade lo que un esquema no dice: el tamaño aproximado de las tablas, qué columnas suelen ser NULL y qué significan los términos de negocio. “Un cliente activo es el que tiene un pedido en los últimos 90 días” evita una suposición errónea.

Un prompt para una consulta:

Using schema.sql: write a PostgreSQL query that returns, for each country,
the number of active customers (an order in the last 90 days) and their
total order value this year. Exclude soft-deleted customers
(deleted_at IS NOT NULL). orders has about 20M rows, customers 400k.
Run it on the dev database, show me the first 10 rows and the EXPLAIN plan.

Usa un usuario de solo lectura para el agente

Antes de que un agente ejecute nada contra una base de datos, dale su propio usuario que no pueda cambiar datos. En PostgreSQL 14 y posteriores, el rol integrado pg_read_all_data lo deja en pocas líneas:

CREATE ROLE agent_ro LOGIN PASSWORD 'change-me';
GRANT pg_read_all_data TO agent_ro;
ALTER ROLE agent_ro SET default_transaction_read_only = on;
ALTER ROLE agent_ro SET statement_timeout = '30s';

pg_read_all_data concede acceso de lectura a todas las tablas, sin permisos de escritura. Las dos líneas ALTER ROLE añaden una protección extra: las transacciones empiezan en solo lectura y una consulta descontrolada se cancela a los 30 segundos. En versiones anteriores, o si quieres un acceso más restringido, concede en su lugar CONNECT, USAGE sobre el esquema y SELECT sobre las tablas que quieras.

Apunta este usuario a una base de datos de desarrollo o staging con datos realistas, no a producción. Si necesitas cifras de producción, usa una réplica de lectura o una copia anonimizada reciente.

Lee el plan de la consulta

Una consulta que devuelve las filas correctas puede tardar minutos. Pide al agente que ejecute EXPLAIN en todo lo que toque una tabla grande y que te explique el plan:

EXPLAIN (ANALYZE, BUFFERS)
SELECT c.country, count(DISTINCT c.id)
FROM customers c
JOIN orders o ON o.customer_id = c.id
WHERE o.created_at > now() - interval '90 days'
  AND c.deleted_at IS NULL
GROUP BY c.country;

EXPLAIN a secas muestra el plan que usaría la base de datos. ANALYZE ejecuta de verdad la consulta y añade tiempos y recuentos de filas reales. Esto importa: EXPLAIN ANALYZE sobre un UPDATE o un DELETE cambia datos de verdad. Envuélvelos en una transacción que deshagas con rollback, o ejecútalos solo en una copia.

Qué pedirle al agente que busque:

  • Escaneos secuenciales en tablas grandes cuando filtras unas pocas filas.
  • Filas estimadas y reales muy distintas, lo que apunta a estadísticas desactualizadas (ANALYZE tablename las refresca).
  • Ordenaciones o hashes que se vuelcan a disco.
  • Bucles anidados sobre muchas filas donde un hash join saldría más barato.

Un buen prompt de seguimiento: “Explícame este plan con palabras sencillas. ¿Qué paso tarda más y por qué? Propón un cambio y muéstrame el nuevo plan.”

Pide índices, con sus contrapartidas

A los agentes les gusta sugerir índices. Cada uno acelera algunas lecturas, ralentiza todas las escrituras en esa tabla y ocupa disco. Pide el razonamiento:

The query above does a sequential scan on orders. Suggest at most one
index, explain which queries it helps and what it costs on writes,
and show the EXPLAIN plan with it on the dev database.

En una tabla con mucho tráfico, crea el índice sin bloquear las escrituras:

CREATE INDEX CONCURRENTLY idx_orders_customer_created
  ON orders (customer_id, created_at);

CONCURRENTLY tarda más, pero no bloquea inserciones ni actualizaciones mientras se ejecuta. No puede ejecutarse dentro de un bloque de transacción, y eso importa porque muchas herramientas de migración envuelven cada migración en una transacción; comprueba cómo lo gestiona la tuya (la mayoría tiene una opción para desactivar la transacción en una migración concreta). Si una creación concurrente falla, deja atrás un índice inválido que tendrás que borrar y volver a crear.

Escribe migraciones seguras de ejecutar

Una migración se ejecuta sobre datos vivos, a menudo mientras la app atiende tráfico. Estos son los patrones que debes pedirle a tu agente y comprobar en lo que entrega.

Expandir, migrar, contraer

No renombres ni borres en un solo paso. Para renombrar users.name a users.full_name:

  1. Expandir: añade full_name como columna que admite NULL. Despliega código que escriba en ambas columnas.
  2. Migrar: rellena full_name a partir de name por lotes. Cambia las lecturas a full_name.
  3. Contraer: en una release posterior, cuando nada lea ya name, bórrala.

Cada paso se puede desplegar y revertir por separado. Un único ALTER TABLE ... RENAME COLUMN rompe todas las instancias en marcha del código antiguo en el momento en que se ejecuta.

Evita bloqueos largos

Algunas sentencias DDL toman un bloqueo que impide lecturas o escrituras mientras se ejecutan. Pide al agente que las señale y use la forma más segura:

ArriesgadoMás seguro
CREATE INDEX en una tabla grandeCREATE INDEX CONCURRENTLY
Añadir una clave foránea en un solo pasoADD CONSTRAINT ... NOT VALID y luego VALIDATE CONSTRAINT en un paso aparte
SET NOT NULL en una tabla grandeAñade un CHECK (col IS NOT NULL) NOT VALID, valídalo y luego pon NOT NULL
Cambiar el tipo de una columnaAñade una columna nueva, rellénala, cambia a ella y borra la antigua
Un único UPDATE enorme para rellenar datosLotes de unos pocos miles de filas

Desde PostgreSQL 11, añadir una columna con un valor por defecto constante no reescribe la tabla, así que eso suele ser barato. Pon además un tiempo máximo de espera de bloqueo al principio de la migración, para que falle rápido en lugar de quedarse en cola detrás de una consulta larga y bloquear todo lo que venga detrás:

SET lock_timeout = '5s';

Hazla reversible

Toda migración debería tener un camino de vuelta, ya sea una migración down o un paso de rollback por escrito. Pídelo explícitamente: “Escribe la migración up y la down, y dime qué pasos no se pueden deshacer sin perder datos.” Borrar una columna no se revierte con una migración down; los datos ya no están. Es otro motivo para borrar en un paso posterior y separado, después de una copia de seguridad.

Pruébala en una copia

Ejecuta la migración en una copia de los datos antes de producción: una base de datos de staging restaurada desde una copia de seguridad reciente, o una base de datos local con datos falsos del tamaño de producción. Comprueba tres cosas: que termina, cuánto tarda y que la app sigue funcionando con el nuevo esquema. Luego ejecuta la migración down y compruébala también.

Con un ORM: deja que genere y que el agente revise

Si usas un ORM, el flujo más seguro es: cambia el modelo, deja que el ORM genere la migración y haz que el agente revise el SQL generado.

ORMGenerar una migraciónAplicarVer el SQL
Prismanpx prisma migrate dev --name add_invoice --create-onlynpx prisma migrate deployel archivo migration.sql que crea
Drizzlenpx drizzle-kit generatenpx drizzle-kit migratelos archivos SQL de tu carpeta de migraciones
Djangopython manage.py makemigrationspython manage.py migratepython manage.py sqlmigrate app 0004
Railsbin/rails generate migration AddFullNameToUsersbin/rails db:migratedb/schema.rb y el archivo de la migración

El --create-only de Prisma escribe la migración sin aplicarla, así que puedes editar antes el SQL, por ejemplo para añadir CONCURRENTLY o dividir un paso. Drizzle también tiene drizzle-kit push, que aplica los cambios de esquema directamente sin archivos de migración; es práctico para prototipar en local, pero usa migraciones generadas para todo lo compartido.

Un prompt de revisión que funciona con cualquiera de ellos:

Read the new migration in prisma/migrations/. For each statement, tell me:
does it lock the table, can it lose data, how long will it take on a
table with 20M rows, and is there a safer form? Don't change any files.

Conectar un agente a una base de datos con MCP

Un servidor MCP permite al agente consultar la base de datos por su cuenta: listar tablas, ejecutar un SELECT, leer un plan. Es útil, y también es donde está el riesgo, así que empieza en solo lectura.

Supabase ofrece un servidor MCP alojado. A octubre de 2026, añadir read_only=true a su URL ejecuta todas las consultas como un usuario de Postgres de solo lectura, y project_ref lo limita a un proyecto:

claude mcp add --transport http supabase \
  "https://mcp.supabase.com/mcp?project_ref=<your-project-ref>&read_only=true"

La propia recomendación de Supabase es conectar un proyecto de producción solo cuando la tarea necesite de verdad datos de producción, y en ese caso con el alcance limitado al proyecto y el modo de solo lectura activado; mantener la aprobación manual de las llamadas a herramientas; y revisar los resultados antes de actuar, porque las protecciones contra la inyección de prompts no son infalibles.

PostgreSQL sin más: usa un servidor MCP de Postgres mantenido con tu usuario agent_ro en la cadena de conexión. Los mejores servidores MCP para programar enumera opciones y sus ajustes de solo lectura. El antiguo servidor Postgres de referencia del proyecto MCP está archivado.

Las reglas que vale la pena escribir en tu CLAUDE.md o AGENTS.md:

## Database
- The database MCP server is read-only. Never ask for write access.
- Schema changes go through migrations in prisma/migrations, never direct DDL.
- Never run UPDATE or DELETE without a WHERE clause.
- Run new queries with EXPLAIN on the dev database before proposing them.

Nunca des a un agente acceso de escritura a producción

Esta es la única regla que no se dobla. Las filas de datos pueden contener texto que parece una instrucción (un ticket de soporte, la bio de un usuario), y un agente que las lea puede seguirlas; eso es inyección de prompts. Una petición malentendida puede convertirse en un DELETE con el filtro equivocado. Con un usuario de solo lectura, lo peor que puede pasar es una consulta lenta. Con acceso de escritura, es una caída o datos perdidos.

El reparto seguro: el agente escribe y prueba el SQL con datos de desarrollo; tú lo revisas; una herramienta de migración o una persona lo aplica en producción. Seguridad de los agentes de programación con IA trata el sandboxing y los permisos de forma más amplia.

Cómo hacerlo en AgentVera

AgentVera es una app de escritorio para macOS, Windows y Linux que ejecuta Claude Code, Codex y otros agentes CLI uno al lado de otro. Algunas funciones están hechas justo para este trabajo:

  • Gestor de bases de datos: conexiones a PostgreSQL, MySQL/MariaDB y SQLite en la misma ventana que tus agentes, con una vista de tabla editable, un editor SQL con EXPLAIN, un diseñador de tablas que muestra el DDL antes de aplicarlo y un diagrama ER. Las conexiones marcadas como de solo lectura también se abren en solo lectura en el lado del servidor, y una conexión marcada como producción se muestra en rojo y pide confirmación antes de aplicar cambios. Puedes dejar que los agentes usen una conexión mediante la herramienta integrada agentvera-db: el acceso está desactivado por defecto, empieza en modo de solo lectura cuando lo activas, los agentes nunca ven la contraseña y cada consulta que ejecutan queda registrada. El gestor de bases de datos está en los planes Pro y Team.
  • DB Guard: cuando un agente termina un turno, los archivos de migración modificados se analizan en busca de riesgos como DROP, TRUNCATE, UPDATE o DELETE sin WHERE, CREATE INDEX sin CONCURRENTLY, restricciones nuevas y pasos down que faltan. Con una conexión similar a producción seleccionada, el riesgo se ajusta según el tamaño real de las tablas. Puedes probar la migración en una base de datos sombra dentro de una transacción que siempre se deshace, o devolver los hallazgos al agente para que los corrija.
  • Gestor de MCP: configura un servidor MCP de base de datos una vez y se conecta a tus agentes en cada arranque.
  • Revisión de código: un segundo modelo revisa el código de migraciones y consultas que escribió el agente cuando termina su turno.

Descarga AgentVera y pruébalo con una base de datos de desarrollo.

Para terminar

Dale al agente el esquema real y un usuario de solo lectura sobre datos de desarrollo. Pídele que ejecute EXPLAIN y explique el plan, que justifique cada índice y que escriba las migraciones en pasos pequeños y reversibles de expandir y contraer, con DDL que no bloquee. Deja que tu ORM genere las migraciones y que el agente las revise, prueba cada una en una copia y guarda para ti las escrituras en producción. Unas instrucciones claras lo facilitan todo; cómo escribir prompts para agentes de programación con IA trata con más detalle el contexto, los planes y los criterios de terminado.

Preguntas frecuentes

¿Puede la IA escribir SQL correcto?

A menudo, si ve tu esquema real y la forma de tus datos. La mayoría de las consultas erróneas vienen de nombres de columna inventados, joins que faltan o NULL que no conocía. Dale al agente el esquema, algunas filas de ejemplo y el resultado esperado, y haz que ejecute la consulta en una base de datos de desarrollo antes de fiarte.

¿Es seguro conectar un agente de programación a mi base de datos?

A una base de datos de desarrollo o staging con un usuario de solo lectura, sí, con cuidado. A producción con permisos de escritura, no. Un agente puede malinterpretar una petición, seguir una instrucción inyectada en los datos o ejecutar un DELETE sin WHERE. Deja las escrituras detrás de una migración que revisas y aplicas tú.

¿Cómo le doy a un agente de IA el esquema de mi base de datos?

Señálale el archivo de esquema que mantiene tu ORM (schema.prisma, los archivos de esquema de Drizzle, los modelos de Django) o vuelca solo la estructura, por ejemplo con pg_dump --schema-only. Un servidor MCP de base de datos de solo lectura también permite al agente listar tablas y columnas por su cuenta.

¿Debe escribir la migración la IA o el ORM?

Deja que el ORM genere la migración a partir del cambio en tu modelo y luego haz que el agente revise el SQL generado en busca de bloqueos, pérdida de datos y pasos que falten. Escribe SQL a mano (o con el agente) solo para lo que el ORM no puede expresar, como la creación concurrente de índices o el relleno de datos.

¿Qué es el patrón expandir y contraer?

Una forma de cambiar un esquema sin tiempo de inactividad. Primero expandes: añades la nueva columna o tabla junto a la antigua. Luego migras: despliegas código que escribe en ambas y rellenas las filas antiguas. Por último contraes: cuando nada lee ya la estructura antigua, la eliminas en una migración posterior.

Reúne a tus agentes en un mismo escritorio.

Descarga AgentVera gratis; tus CLI instaladas ya están listas.

Más artículos