Be Software Architecture Wise
Be Wise Apps

Read in English · Lire en français · Auf Deutsch lesen

Sección 0.5 de 0.8 · Principiante · 18 min de lectura

Archivos y bases de datos: almacenamiento relacional y no relacional, consultas y transacciones

Videolección

5 min · narrado en inglés, con subtítulos
Solo escuchar (audio)
Leer la transcripción

Un programa en ejecución mantiene sus datos de trabajo en memoria, que lo olvida todo cuando el programa se detiene. Todo lo que deba sobrevivir, como la cuenta de un cliente o un pedido, tiene que escribirse en un almacenamiento. Piensa en una base de datos como en una biblioteca con un bibliotecario cuidadoso. Mantiene un catálogo, comprueba que cada registro cumple las reglas y nunca pierde un cambio que ha prometido conservar.

La forma más sencilla de guardar datos es un archivo. Los archivos son excelentes para cosas que por naturaleza son documentos completos, como imágenes, archivos PDF, videos y logs. Pero imagina una tienda que guarda todos sus pedidos en un único archivo de hoja de cálculo. Dos clientes pagan en el mismo instante. ¿Qué cambio prevalece? El servidor se cae a mitad del guardado. ¿Queda ahora el archivo mitad antiguo y mitad nuevo? Y alguien escribe un número de cliente que no existe. ¿Quién se lo impide? Cada programa que usara el archivo tendría que resolver cada uno de estos problemas por su cuenta.

Un sistema de gestión de bases de datos resuelve estos problemas una sola vez, para todos. Las aplicaciones, como la app web de una tienda y una herramienta de informes, nunca tocan directamente los archivos de datos. Envían solicitudes escritas en un lenguaje llamado SQL. El sistema de gestión de bases de datos comprueba las reglas, planifica cómo responder a cada pregunta y gestiona muchos usuarios a la vez. Escribe los datos en archivos en disco y anota cada cambio, en orden, en un registro. Y se envían periódicamente copias de ambos a un almacenamiento de copias de seguridad en una ubicación separada.

El tipo más utilizado es la base de datos relacional. Los datos viven en tablas. Cada tabla describe un tipo de cosa. Cada fila es una instancia, como un cliente, y cada columna es un dato sobre ella, como su correo electrónico. Cada tabla tiene una clave primaria, un valor que es único para cada fila, como el identificador del cliente. Un pedido también contiene un identificador de cliente. Eso es una clave foránea: apunta a una fila de la tabla de clientes. La base de datos rechazará un pedido para un cliente que no existe. Cada dato se guarda una sola vez. Un pedido puede contener muchos productos, así que una tabla de enlace, la de líneas de pedido, registra una fila por producto y pedido. Responder a una pregunta obliga entonces a combinar tablas, lo que SQL hace con un join.

¿Cómo encuentra la base de datos los datos rápidamente? Supón que una tabla de pedidos tiene diez millones de filas y una pantalla de soporte necesita los veinte pedidos de un cliente. Sin ayuda, la base de datos tiene que leer cada una de las filas y comprobarla. Eso se llama recorrido completo de la tabla. Un índice funciona como el índice al final de un libro. Es un árbol ordenado, de solo tres o cuatro niveles de profundidad, así que la base de datos lee unas pocas páginas y va directamente a las veinte filas. Si la tabla se multiplica por diez, el recorrido hace diez veces más trabajo. El índice añade como mucho un nivel más. Pero los índices no son gratis. Cada pedido nuevo debe actualizar también el índice, y este ocupa espacio. Es otra vez ese intercambio de espacio por velocidad.

Mover cien libras de Alice a Bob requiere dos cambios. Si el servidor se cae entre ambos, el dinero desaparece. Una transacción hace que los cambios tengan éxito juntos o no se produzcan en absoluto. Sus garantías se llaman ACID. Atomicidad significa todo o nada. Consistencia significa que las reglas nunca quedan incumplidas. Una regla según la cual los saldos no pueden bajar de cero rechaza una transferencia que Alice no puede pagar. Aislamiento significa que dos transferencias que se ejecutan a la vez no pueden basarse ambas en el mismo saldo antiguo. Y durabilidad significa que, cuando la app dice transferencia completada, el cambio se ha guardado de verdad y sobrevive a una caída o a un corte de corriente.

Las bases de datos relacionales no son la única opción. NoSQL es un nombre genérico para las bases de datos que no usan tablas de la misma manera. Las bases de datos documentales guardan registros autónomos, lo que encaja con algo como un catálogo de productos. Los almacenes clave-valor son diccionarios gigantes, para búsquedas muy rápidas, como las de carritos de la compra. Los almacenes de columnas anchas manejan enormes volúmenes de escrituras, como lecturas de sensores, repartidos entre muchas máquinas. Y las bases de datos de grafos responden a preguntas sobre conexiones. Muchos sistemas reales usan más de un tipo, cada uno donde encaja.

Los discos fallan y la gente comete errores, así que los datos necesitan copias de seguridad guardadas en un lugar separado. Y una copia de seguridad que nunca se ha restaurado es una esperanza, no una copia de seguridad. Una réplica, una segunda base de datos que copia la primera, protege contra el fallo de una máquina. Pero un borrado erróneo llega a la réplica en milisegundos. Por último, los datos suelen durar más que el código que los rodea. Las aplicaciones se reescriben cada pocos años; los registros de clientes se conservan durante décadas. Por eso las decisiones sobre dónde viven los datos son de las más costosas de revertir.

La sección completa incluye consultas SQL reales, una transferencia bancaria que funciona y más sobre el esquema de la tienda. A continuación, en la Sección cero punto seis, veremos las API y cómo trabajan juntos sistemas separados.

Lo que necesitas saber

Por qué los programas necesitan un lugar donde guardar los datos

Un programa en ejecución mantiene sus datos de trabajo en memoria (RAM), que es rápida pero lo olvida todo cuando el programa se detiene o la máquina se reinicia (consulta qué es el software). Todo lo que deba sobrevivir a un reinicio, como la cuenta de un cliente, un pedido o una cita en un hospital, tiene que escribirse en un almacenamiento que conserve su contenido sin corriente: un disco duro o una unidad de estado sólido. Los datos que sobreviven de esta forma se llaman persistentes, y decidir cómo persistirlos es una de las primeras decisiones de cualquier sistema y de las que más duran.

La forma más sencilla de persistir datos es un archivo: una secuencia de bytes con nombre que el sistema operativo guarda en disco. Los archivos son excelentes para cosas que por naturaleza son documentos completos: imágenes, PDF, videos, configuración, logs, informes exportados. Los sistemas suelen guardarlos en un almacenamiento de objetos en la nube (un servicio que guarda archivos por nombre) y registrar en otro lugar solo una referencia.

Los archivos se vuelven un problema cuando muchos usuarios leen y modifican a la vez pequeños fragmentos de datos estructurados. Imagina una tienda que guarda todos sus pedidos en un único archivo de hoja de cálculo. Dos clientes pagan en el mismo instante: ¿qué cambio prevalece? El servidor se cae a mitad del guardado: ¿el archivo queda mitad antiguo, mitad nuevo? Un agente de soporte quiere los pedidos de un cliente: ¿tiene el programa que leer el archivo entero? Alguien escribe un número de cliente que no existe: ¿quién se lo impide? Cada programa que usara el archivo tendría que resolver cada uno de estos problemas, y de la misma manera.

Qué es una base de datos

Una base de datos es una colección organizada de datos, y el programa que se ocupa de ella es un sistema de gestión de bases de datos (DBMS), como PostgreSQL, MySQL, Microsoft SQL Server, Oracle Database o SQLite. A menudo se dice "la base de datos" para ambas cosas. El DBMS resuelve los problemas de los archivos una sola vez, para todos: permite que muchos usuarios trabajen a la vez sin pisarse, encuentra los datos rápidamente, rechaza los datos que incumplen las reglas y vuelve a un estado correcto tras una caída.

La analogía es una biblioteca. Un montón de papeles sobre una mesa funciona si eres su único usuario. Una biblioteca tiene un catálogo, reglas sobre dónde va cada cosa, un registro de quién se ha llevado qué y un bibliotecario que no deja que dos personas se lleven el mismo ejemplar. Las aplicaciones no tocan las estanterías; se lo piden al bibliotecario.

En la mayoría de los sistemas empresariales, el DBMS se ejecuta como un proceso servidor propio, a menudo en su propia máquina, y las aplicaciones se comunican con él a través de la red (consulta cómo se comunican las computadoras). SQLite es una excepción muy conocida: es una biblioteca que se ejecuta dentro de la aplicación y guarda toda la base de datos en un único archivo, por eso se encuentra en teléfonos, navegadores y pequeñas herramientas.

Dónde viven realmente los datos

Las aplicaciones envían SQL a un servidor de BD, cuyo DBMS escribe archivos de datos y un registro en disco, copiados a un almacén de copias aparteMáquina servidor de BDApp web tiendalee y escribeApp de informessolo leeSQLSQLDBMSvalida reglasplan. consultasgestiona transaccionesArch. datostablas e índicesRegistro transac.cada cambio, en ordenAlmacén copiasubicación separadacopias regulares
Las aplicaciones nunca escriben directamente en los archivos de la base de datos: envían solicitudes al DBMS, que escribe los archivos de datos y un registro, y un proceso aparte copia ambos al almacenamiento de copias de seguridad.

Bases de datos relacionales: tablas, claves y relaciones

El tipo de base de datos más utilizado es la base de datos relacional, basada en un modelo publicado por Edgar F. Codd, de IBM, en 1970. Los datos viven en tablas. Cada tabla describe un tipo de cosa (clientes, pedidos, productos). Cada fila es una instancia de esa cosa (un cliente), y cada columna es un dato sobre ella (nombre, dirección de correo electrónico, fecha de alta), con un tipo declarado, como entero, texto, fecha o decimal.

Cada tabla tiene una clave primaria: una columna (o combinación de columnas) cuyo valor es único para cada fila y nunca está vacío, como customer_id. Una clave foránea es una columna de una tabla que contiene la clave primaria de una fila de otra tabla. Un pedido tiene una columna customer_id, que indica qué cliente lo hizo. Declararla como clave foránea le indica al DBMS que rechace un pedido para el cliente 999 si no existe ningún cliente 999: esto se llama integridad referencial.

El conjunto completo de tablas, columnas, tipos, claves y reglas es el esquema. El esquema es un contrato: cada programa que usa la base de datos puede confiar en que un pedido siempre tiene un cliente válido y un precio que es un número. Cambiar un esquema más adelante, cuando millones de filas y varios programas dependen de él, es posible pero exige cuidado, y por eso la evolución del esquema tiene su propia sección en el Capítulo 7.

Los diseños relacionales intentan guardar cada dato una sola vez. La dirección de correo electrónico del cliente vive en una fila de la tabla de clientes, no copiada en cada pedido. Esto se llama normalización. Significa que una actualización ocurre en un solo lugar y no puede dejar atrás copias contradictorias. El precio de este orden es que responder a una pregunta a menudo obliga a combinar tablas, que es para lo que sirven los joins.

Hacer preguntas con SQL

SQL (Structured Query Language, que se pronuncia "ese-cu-ele" o, en inglés, "sequel") es el lenguaje que se usa para trabajar con bases de datos relacionales. Se desarrolló en IBM en la década de 1970 y se convirtió en norma ANSI e ISO a finales de la década de 1980; todos los DBMS relacionales importantes lo hablan, cada uno con pequeñas diferencias de dialecto. SQL es declarativo: describes el resultado que quieres, no los pasos para encontrarlo. El planificador de consultas del DBMS elige los pasos, por ejemplo si leer una tabla entera o usar un índice.

Un join combina filas de dos o más tablas haciendo coincidir columnas, normalmente una clave foránea con la clave primaria a la que remite. La segunda consulta de abajo lista cada línea de los pedidos de un cliente junto con el nombre del producto, usando tres tablas a la vez.

-- One customer's orders since 1 October, newest first
SELECT order_id, status, placed_at
FROM orders
WHERE customer_id = 42
  AND placed_at >= '2026-10-01'
ORDER BY placed_at DESC;

-- Each order line with the product's name (a join)
SELECT o.order_id, p.name, i.quantity, i.unit_price
FROM orders AS o
JOIN order_items AS i ON i.order_id = o.order_id
JOIN products AS p ON p.product_id = i.product_id
WHERE o.customer_id = 42;
Dos consultas sobre el esquema de la tienda que se muestra más adelante en esta sección: un SELECT filtrado y un JOIN de tres tablas.

INSERT, UPDATE y DELETE modifican datos, y CREATE TABLE define el esquema. El código de las aplicaciones suele enviar SQL a través de un mapeador objeto-relacional (ORM), una biblioteca que convierte filas en objetos. Los ORM ahorran escritura, pero ocultan el SQL que realmente se envía; un problema de rendimiento clásico es un ORM que lanza sin avisar una consulta por fila en lugar de un único join.

Índices: el índice del libro, no el libro entero

Sin ayuda, la única forma que tiene la base de datos de encontrar todos los pedidos del cliente 42 es leer cada fila de la tabla de pedidos y comprobarla una por una: un recorrido completo de la tabla, que es O(n) en la notación de datos y algoritmos. Un índice de base de datos es una estructura de datos adicional y ordenada que relaciona los valores de una columna con las filas que los contienen, igual que el índice al final de un libro relaciona palabras con números de página. La mayoría de las bases de datos relacionales usan por defecto un árbol B (B-tree), un árbol ancho, poco profundo y siempre equilibrado que encuentra un valor en O(log n) pasos.

Las claves primarias se indexan automáticamente. Los demás índices se añaden de forma deliberada, para las columnas por las que las consultas filtran, combinan u ordenan: CREATE INDEX idx_orders_customer ON orders (customer_id);. Los índices no son gratis. Cada inserción, actualización o borrado debe actualizar también cada índice de la tabla, y cada índice ocupa espacio en disco y memoria. Una tabla con quince índices lee rápido y escribe despacio. Elegir índices es un compromiso guiado por las consultas que el sistema ejecuta realmente, lo que constituye un primer ejemplo del compromiso entre espacio y tiempo que atraviesa toda la arquitectura.

Ejemplo práctico

Ejemplo práctico: encontrar los pedidos de un cliente

Una tienda tiene 10 millones de filas en su tabla de pedidos. La pantalla de atención al cliente pide todos los pedidos de un cliente, unas 20 filas.

Sin índiceRecorrido completo de la tabla: la base de datos lee y comprueba las 10 000 000 de filas para encontrar las 20 que coinciden.
Con un índice de árbol B sobre customer_idCada página del índice contiene cientos de claves, así que el árbol solo tiene tres o cuatro niveles de profundidad. La base de datos lee unas pocas páginas del índice y después recupera las 20 filas que coinciden.
CrecimientoSi la tabla crece hasta 100 millones de filas, el recorrido hace diez veces más trabajo; la búsqueda en el índice añade como mucho un nivel más.
Costo pagado en otra parteCada pedido nuevo escribe ahora en la tabla y en el índice. El uso de disco crece en el tamaño del índice.

Esto es O(n) frente a O(log n), de la Sección 0.2: a menudo, la diferencia entre una respuesta en segundos y una en milisegundos. Muchas quejas por consultas lentas en sistemas jóvenes se resuelven con el índice adecuado, no con hardware más grande.

Transacciones y ACID: la transferencia bancaria

Mover 100 libras de la cuenta de Alice a la de Bob requiere dos cambios: restar 100 a Alice y sumar 100 a Bob. Si el servidor se cae después del primer cambio y antes del segundo, 100 libras han desaparecido. Si dos transferencias desde la cuenta de Alice se ejecutan a la vez, ambas podrían ver un saldo de 150 y ambas podrían tener éxito, dejándola en descubierto. Una transacción agrupa varias operaciones en una unidad de trabajo que o bien se completa por entero (commit) o bien no tiene ningún efecto (rollback).

Las garantías que ofrece una transacción se resumen como ACID, un acrónimo acuñado por Theo Härder y Andreas Reuter en 1983, a partir de trabajos anteriores de Jim Gray:

PropiedadQué prometeEn la transferencia bancaria
AtomicidadTodos los cambios de la transacción se producen, o no se produce ninguno.Nunca se carga dinero a Alice sin abonárselo a Bob.
ConsistenciaUna transacción lleva la base de datos de un estado válido a otro; las reglas, como las claves y las comprobaciones, nunca quedan incumplidas.Una regla según la cual los saldos no pueden bajar de cero rechaza una transferencia que Alice no puede pagar.
AislamientoLas transacciones que se ejecutan a la vez no ven el trabajo a medio terminar de las demás; el resultado es como si se hubieran ejecutado una tras otra (en la medida que fije el nivel de aislamiento).Dos transferencias simultáneas desde la cuenta de Alice no pueden basarse ambas en el mismo saldo antiguo.
DurabilidadUna vez que la base de datos confirma un commit, el cambio sobrevive a una caída o a un corte de corriente.Cuando la app dice "Transferencia completada", el dinero se ha movido de verdad, porque el cambio ya está en el registro en disco.
import sqlite3

conn = sqlite3.connect("bank.db")
# The accounts table was created with CHECK (balance >= 0)

def transfer(from_id, to_id, amount):
    try:
        with conn:  # one transaction: commit on success, rollback on error
            debit = conn.execute(
                "UPDATE accounts SET balance = balance - ? WHERE id = ?",
                (amount, from_id))
            credit = conn.execute(
                "UPDATE accounts SET balance = balance + ? WHERE id = ?",
                (amount, to_id))
            if debit.rowcount != 1 or credit.rowcount != 1:
                raise ValueError("No such account")  # forces a rollback
        return "Transfer complete"
    except (sqlite3.Error, ValueError):
        return "Transfer refused: no account was changed"
Una transferencia con el módulo sqlite3 integrado en Python. El bloque with hace commit si ambas actualizaciones tienen éxito y hace rollback si alguna falla o si una cuenta no existe.

Fíjate en la comprobación de rowcount (el número de filas que ha cambiado cada actualización): para la base de datos, una actualización que no coincide con ninguna cuenta no es un error, así que el propio código debe tratarla como tal. Hay otros dos detalles importantes más allá de este ejemplo. Los marcadores ? pasan los valores por separado del texto SQL, que es la defensa estándar contra la inyección SQL, un ataque en el que la entrada del usuario se cuela en una consulta como si fuera código (el Capítulo 8 vuelve sobre esto). Y la promesa de durabilidad se cumple gracias a un registro de escritura anticipada (write-ahead log): el DBMS anota cada cambio en un registro en disco al que solo se añaden datos antes de confirmar el commit, de modo que tras una caída puede repetir o deshacer trabajo hasta llegar a un estado correcto.

El aislamiento es la propiedad más sutil. El aislamiento completo (llamado serializable) es seguro pero limita cuánto trabajo puede ejecutarse en paralelo, así que las bases de datos ofrecen niveles de aislamiento más débiles que cambian algo de protección por velocidad, y muchas usan por defecto un nivel más débil. Qué anomalías permite cada nivel se trata en transacciones y aislamiento. Por ahora, la idea clave es que una sola base de datos ofrece garantías fuertes y bien conocidas dentro de una transacción, y que esas garantías son mucho más difíciles de conseguir cuando los datos están repartidos entre varias bases de datos o servicios.

NoSQL: otras formas de datos

Las bases de datos relacionales no son la única opción. NoSQL es un nombre genérico, popularizado en un encuentro de 2009 en San Francisco, para las bases de datos que no usan el modelo relacional. Surgieron para manejar volúmenes muy grandes repartidos entre muchas máquinas, formas de datos flexibles y patrones de acceso que las tablas atienden con dificultad. El nombre dice lo que no son, así que abarca familias bastante distintas.

Las cuatro principales familias NoSQL

FamiliaCómo guarda los datosEncaja bien conEjemplos
Base de datos documentalCada registro es un documento autónomo, normalmente similar a JSON, que puede anidar listas y subobjetos. Los documentos de una misma colección no tienen por qué compartir exactamente los mismos campos.Datos que se leen y escriben como un todo: un catálogo de productos con atributos variados, un perfil de usuario, el contenido de una página web.MongoDB, Couchbase, Firestore
Almacén clave-valorUn diccionario gigante: una clave única se asocia a un valor en cuyo interior la base de datos no mira. La búsqueda es solo por clave.Búsquedas simples muy rápidas: sesiones, carritos de la compra, cachés, feature flags.Redis, Amazon DynamoDB, etcd
Almacén de columnas anchasFilas identificadas por una clave, cada una con muchas columnas, agrupadas y repartidas (particionadas) entre muchas máquinas. Las tablas se diseñan en torno a las consultas que se van a ejecutar.Enormes volúmenes de escrituras, como lecturas de sensores, logs de eventos e historiales de mensajería, entre muchos servidores y centros de datos.Apache Cassandra, Apache HBase, Google Bigtable
Base de datos de grafosNodos (cosas) y aristas (relaciones), ambos con propiedades, como en los grafos de la Sección 0.2.Preguntas sobre conexiones: amigos de amigos, redes de fraude, planificación de rutas, recomendaciones.Neo4j, Amazon Neptune

Los profesionales no se ponen de acuerdo sobre la opción por defecto. Un grupo dice que hay que empezar con una base de datos relacional salvo que haya un motivo claro para no hacerlo: SQL es ampliamente conocido, las transacciones y los joins son potentes, y los sistemas relacionales modernos también guardan bien documentos JSON. El otro grupo dice que hay que elegir desde el principio el almacén que encaje con el patrón de acceso, porque un almacén documental o clave-valor puede ser más sencillo y escalar de forma más barata con la carga de trabajo adecuada. Ambos coinciden en que muchos sistemas reales usan más de un tipo, cada uno donde encaja, lo que se llama persistencia políglota. La sección del Capítulo 7 sobre cómo elegir una base de datos ofrece una forma estructurada de decidir.

Ejemplo práctico: el esquema de una tienda en línea

Piensa en una pequeña tienda en línea. Necesita saber quiénes son sus clientes, qué vende y quién ha pedido qué. Un primer intento podría ponerlo todo en una sola tabla con una fila por pedido y las columnas product1, product2, product3. Eso se rompe en cuanto alguien pide cuatro cosas, y copia el nombre y la dirección del cliente en cada pedido.

Esquema de una tienda en línea: los pedidos remiten a clientes, y las líneas de pedido a pedidos y a productosde clientescustomer_id (PK)nameemailcreated_atordersorder_id (PK)customer_id (FK)statusplaced_atorder_itemsorder_id (PK, FK)product_id (PK, FK)quantityunit_priceproductsproduct_id (PK)namepricestockCada flecha va de una clave foránea (FK) a la clave primaria (PK) a la que remite.
Un esquema de tienda normalizado: cada dato se guarda una sola vez y las claves foráneas registran las relaciones.

Ejemplo práctico

Ejemplo práctico: por qué el esquema tiene cuatro tablas

El esquema anterior responde a las preguntas de la tienda sin copiar datos.

de clientesUna fila por persona. Cambiar una dirección de correo electrónico cambia una fila.
ordersUna fila por compra. customer_id es una clave foránea, así que cada pedido pertenece a un cliente real. Un cliente tiene muchos pedidos: una relación uno a muchos.
productsUna fila por artículo a la venta, con el precio y el nivel de existencias actuales.
order_itemsUn pedido contiene muchos productos y un producto aparece en muchos pedidos: una relación muchos a muchos. Las bases de datos relacionales la representan con una tabla de enlace, con una fila por producto y pedido.
Copia deliberada: unit_priceEl precio se copia en order_items cuando se hace el pedido. No es un error de normalización: el pedido debe registrar lo que el cliente pagó realmente, aunque el precio del catálogo cambie la semana que viene.
Hacer un pedidoInsertar el pedido, insertar sus artículos y reducir las existencias de cada producto ocurren en una sola transacción, de modo que una caída nunca puede dejar un pedido sin artículos ni unas existencias que no se hayan reducido.

Un buen diseño de esquema parte de las preguntas que se hace el negocio y de los datos que nunca debe perder, no de las pantallas de la primera versión de la app.

La misma tienda en una base de datos documental podría guardar cada pedido como un documento con sus artículos anidados dentro, lo que facilita leer un pedido entero de una vez pero dificulta preguntas como "ventas totales por producto".

Copias de seguridad, recuperación y bases de datos gestionadas

Los discos fallan, la gente ejecuta el DELETE equivocado, el software tiene errores y hay atacantes que cifran los datos para pedir un rescate. Una copia de seguridad es una copia de los datos guardada en un lugar separado, a partir de la cual se puede restaurar la base de datos. Hay tres hábitos profesionales importantes. Una copia de seguridad que nunca se ha restaurado es una esperanza, no una copia de seguridad, así que los equipos ensayan las restauraciones y miden cuánto tardan. Las copias se guardan en más de un lugar (una regla práctica habitual es tener tres copias, en dos tipos de soporte, una fuera de las instalaciones). Y una réplica, una segunda base de datos que copia continuamente la primera, protege contra el fallo de una máquina, pero no contra los errores: un DELETE erróneo llega a la réplica en milisegundos. Muchas bases de datos pueden combinar una copia de seguridad completa periódica con el registro de transacciones guardado para restaurar a cualquier momento, lo que se llama recuperación a un punto en el tiempo.

Administrar bien una base de datos (aplicar parches, ajustarla, replicarla, hacer copias de seguridad y restaurarla a las tres de la mañana) es un trabajo especializado que nunca termina, así que los proveedores de nube venden bases de datos gestionadas: Amazon RDS, Azure SQL Database y Google Cloud SQL son ejemplos. El proveedor se encarga de las máquinas, las actualizaciones de software, las copias de seguridad automáticas y el failover a una copia en reserva; el cliente sigue siendo responsable del esquema, las consultas, los índices, los permisos de acceso y el costo. Los servicios gestionados se tratan de forma más amplia en servidores y la nube.

Por qué esto importa para la arquitectura

Los datos suelen durar más que el código que los rodea: las aplicaciones se reescriben cada pocos años, mientras que los registros de clientes y los historiales médicos se conservan durante décadas. Las decisiones sobre dónde viven los datos, qué tipo de base de datos los guarda, qué programa es su propietario y qué garantías necesitan son, por tanto, de las más costosas de revertir. Varias grandes cuestiones de arquitectura surgen directamente de esta sección: si cada servicio debe tener su propia base de datos (propiedad de los datos), qué base de datos sirve para cada trabajo (cómo elegir una base de datos) y cómo mantener los datos correctos cuando una acción de negocio afecta a varias bases de datos, donde ya no se dispone de una única transacción ACID (sagas). Cuando un arquitecto pregunta "¿dónde está la fuente de verdad de esto?", esta sección es el motivo.

Comprueba lo que has entendido

¿Por qué un archivo de hoja de cálculo es un mal lugar para guardar los pedidos de una tienda en línea cuando muchos clientes compran a la vez?

Varios escritores simultáneos pueden sobrescribirse entre sí, una caída a mitad de un guardado puede corromper el archivo, encontrar los pedidos de un cliente obliga a leerlo todo y nada impone reglas como que cada pedido tenga un cliente real. Un DBMS resuelve los cuatro problemas.

En el esquema de la tienda, ¿qué hace que customer_id en la tabla orders sea una clave foránea, y qué te aporta?

Contiene la clave primaria de una fila de la tabla customers y está declarada como referencia a ella. Así, la base de datos rechaza los pedidos de clientes que no existen.

¿Por qué no indexar simplemente todas las columnas de todas las tablas?

Cada índice debe actualizarse en cada inserción, actualización y borrado, y ocupa espacio. Demasiados índices hacen que las escrituras sean lentas y el almacenamiento caro, así que los índices se eligen según las consultas que se ejecutan realmente.

¿Qué propiedad ACID se incumple si una caída deja a Alice con el cargo hecho pero a Bob sin el abono?

La atomicidad: los dos cambios deberían haberse producido juntos o no producirse en absoluto.

Un equipo dice: "tenemos una réplica en otro centro de datos, así que no necesitamos copias de seguridad". ¿Qué se les ha pasado por alto?

Una réplica copia los errores y la corrupción con la misma fidelidad que los datos buenos, así que un borrado accidental o un ataque de ransomware llega a ella en cuestión de momentos. Las copias de seguridad, idealmente con recuperación a un punto en el tiempo, protegen contra eso.

Siguiente · 0.6API e integraciónQué es una API y por qué es un contrato, cómo usan las API REST las URL, los verbos HTTP, los códigos de estado y JSON, y cómo las claves, los webhooks, las colas, las versiones y los límites de tasa determinan la integración.Continuar →

Fuentes y lecturas recomendadas

¿Tienes una pregunta sobre esta sección? ArchitectBot, el asistente de estudio con IA del curso, responde primero a partir del curso.

Pregunta: “Para una pequeña tienda en línea, ¿cómo decido entre una base de datos relacional como PostgreSQL y una base de datos documental como MongoDB?”