Ir al contenido

SQLite es el defecto de Laravel. ¿Cuándo basta?

El valor por defecto cambió y muchas aplicaciones llegaron a producción con él sin que nadie lo decidiera. Los casos en que eso es correcto son reales y más estrechos de lo que sugiere.

4 min de lectura

La base de datos por defecto de Laravel es SQLite, y los valores por defecto son poderosos. Un número nada pequeño de aplicaciones llega hoy a producción con él porque nadie cambió la línea, no porque alguien decidiera que era lo adecuado.

A veces lo es. Aquí es donde cae la línea de verdad.

Qué es genuinamente distinto

No el SQL. No Eloquent, que se comporta igual. Una cosa: SQLite es un fichero que su proceso abre, no un servidor al que su proceso se conecta.

Todo se sigue de ahí. No hay límite de conexiones porque no hay conexiones. No hay latencia de red porque no hay red. Y las escrituras se serializan entre todos los procesos que tocan el fichero, porque un fichero no tiene planificador que arbitre entre clientes.

Active WAL antes que nada. Sin él, un lector bloquea a un escritor y un escritor bloquea a los lectores, que es la configuración que la mayoría mide sin saberlo:

// una migración, o un service provider
DB::statement('PRAGMA journal_mode = WAL');
DB::statement('PRAGMA busy_timeout = 5000');
DB::statement('PRAGMA foreign_keys = ON');

Esas tres son casi obligatorias. WAL deja avanzar a los lectores durante una escritura. El tiempo de espera convierte un error instantáneo de database is locked en una espera corta, que es casi siempre lo que quería. Y las claves foráneas están desactivadas por defecto en SQLite, lo cual sorprende a quien escribió constrained() en una migración y dio por hecho que se estaba imponiendo.

Dónde es la respuesta correcta

Una herramienta interna. Veinte personas, sobre todo leyendo. El ahorro operativo es real: ningún servidor de base de datos que parchear, respaldar, asegurar o pagar, y una copia de seguridad es copiar un fichero.

Una aplicación en un solo servidor con escrituras moderadas. Un sitio de contenido, una página de reservas, un SaaS pequeño en su primer año. SQLite en disco local es más rápido que Postgres por red para un solo lector, porque no cruza un socket.

Las pruebas. Una base SQLite en memoria hace rápida una batería, con la advertencia de más abajo.

Cualquier cosa embebida o desplegada en el borde, donde no hay servidor de base de datos disponible.

Dónde no lo es

Varios servidores de aplicación. Este es el límite duro. Dos servidores web no pueden compartir con seguridad un fichero SQLite sobre un sistema de ficheros de red. Si alguna vez va a escalar horizontalmente, esta decisión hay que tomarla otra vez, y tomarla después es una migración bajo presión.

Trabajo con muchas escrituras. Cualquier cosa que registre cada petición, ingiera eventos o procese una cola en la base de datos. Las escrituras se serializan; eso es el diseño, no un problema de ajuste.

Más de un par de workers de cola. Los workers que consultan una tabla de trabajos son escritores concurrentes. Use Redis para la cola y SQLite para la aplicación, o ejecute un worker y acepte el rendimiento.

Cualquier cosa que necesite recuperación a un punto en el tiempo, replicación o una réplica de lectura. Hay herramientas que añaden replicación sobre SQLite y son una dependencia y una decisión, no un valor por defecto.

La trampa de las pruebas

La decisión sobre SQLite más común en una base de código Laravel no es la de producción. Es :memory: en phpunit.xml, elegida por velocidad, contra una aplicación que ejecuta MySQL o Postgres.

Esa batería no puede cazar:

  • Una violación de restricción que el motor real impone y SQLite no.
  • Una diferencia de colación, que es la trampa de las mayúsculas con otro sombrero.
  • Una migración que bloquea una tabla grande, porque no hay bloqueo ni tabla.
  • Cualquier cosa que use un operador JSON, una función de ventana o un tipo que el motor real tiene y SQLite no.

Es un intercambio razonable para una batería con mucha prueba unitaria y malo como única cosa entre usted y un error de esquema. Ejecute la batería rápida en SQLite si quiere; ejecute la batería que da paso a un despliegue contra el motor al que despliega.

Decidir con honestidad

Hágase una pregunta: ¿va a correr esta aplicación alguna vez en más de un servidor?

Si la respuesta es no y sabe por qué es no - es interna, tiene un techo, es de verdad pequeña - SQLite no es un compromiso. Es menos infraestructura que poseer, y poseer menos infraestructura es un beneficio real que se descarta con demasiada facilidad.

Si la respuesta es sí, o es "probablemente no pero quién sabe", empiece en el motor en el que acabaría. Migrar una aplicación en marcha es trabajo que se evita por completo dedicando diez minutos a esto en la primera semana, que es el mismo argumento que el dinero y las fechas, y se sostiene por la misma razón.

Preguntas relacionadas

¿SQLite es una base de datos de verdad?
Del todo, y probablemente sea la más desplegada del mundo. La pregunta nunca es si es software serio, sino si su modelo de concurrencia encaja con su patrón de escritura, porque esa es la única dimensión en la que difiere de una base de datos cliente-servidor y que no se puede configurar para que desaparezca.
¿Qué se rompe primero al crecer?
Las escrituras concurrentes. SQLite las serializa, así que un segundo escritor espera. Con WAL activado los lectores no se bloquean y un endpoint con muchas escrituras bajo tráfico real sigue haciendo cola detrás de sí mismo, y el síntoma es un tiempo de espera de bloqueo en lugar de una consulta lenta, lo que manda a la gente a buscar en el sitio equivocado.
¿Podemos usarlo con workers de cola?
Con cuidado, y normalmente no con el driver de cola en base de datos. Varios workers consultando una tabla de trabajos son varios escritores concurrentes contra una base de datos diseñada para uno cada vez. Use Redis para la cola, o acepte un único worker.
¿Cómo salimos de él después?
El esquema y el código Eloquent se mueven casi sin cambios; los datos hay que exportarlos y la tipificación laxa hay que revisarla. SQLite acepta una cadena en una columna entera, así que un volcado puede contener valores que el destino rechaza. Valide antes de migrar, no durante.

← Volver a todos los artículos

Llamar+1 848 272 7583WhatsApp+90 850 308 5436Correoinfo@codefacture.comPágina de contacto