SQLite es un motor embebido, lo que significa que la base de datos y la aplicación comparten el mismo espacio de memoria y ciclo de vida. Aunque esto elimina la latencia de red, impone restricciones arquitectónicas severas que deben evaluarse antes de adoptarlo en producción.
2.1. Concurrencia de Escritura y Bloqueos (Locking)
La limitación más crítica de SQLite radica en su modelo de concurrencia. A diferencia de PostgreSQL o MySQL, que utilizan bloqueos a nivel de fila (row-level locking), SQLite bloquea el archivo completo durante las escrituras.
- Sin WAL (Write-Ahead Logging): Lecturas y escrituras se bloquean mutuamente. Una escritura exclusiva bloquea todas las lecturas.
- Con WAL (Activado mediante PRAGMA): Permite múltiples lectores concurrentes junto a un único escritor. Sin embargo, las escrituras concurrentes siguen siendo serializadas. Si múltiples hilos intentan escribir simultáneamente, SQLite encolará las operaciones o lanzará un error
OperationalError: database is lockedsi se supera el tiempo de espera (timeout).
Conclusión arquitectónica: SQLite no es apto para sistemas con alta tasa de transacciones de escritura concurrentes (High Write Throughput).
2.2. Inviabilidad en Sistemas de Archivos en Red (NFS)
Desplegar una base de datos SQLite en un volumen de red (NFS, SMB, EFS) es un antipatrón de diseño documentado.
La integridad de las transacciones en SQLite depende de la implementación precisa de los bloqueos POSIX (o equivalentes en Windows) a nivel del sistema de archivos. Muchos clientes NFS tienen implementaciones de bloqueo defectuosas (o latencias excesivas), lo que invariablemente conduce a la corrupción de la base de datos o a bloqueos “fantasma” irrecuperables.
2.3. Tipado Dinámico (Manifest Typing)
Históricamente, SQLite utiliza un sistema de tipado dinámico. El tipo de dato está asociado al valor en sí, no a la columna. Puedes insertar una cadena de texto en una columna definida como INTEGER sin que el motor lance una excepción. Esto traslada la responsabilidad de la integridad y validación de datos a la capa de la aplicación (Python), lo cual es propenso a errores en arquitecturas complejas.
Mitigación en versiones modernas (SQLite >= 3.37.0):
Para imponer el tipado estático tradicional, es imperativo declarar las tablas con la cláusula STRICT.
-- Ejemplo de declaración de tabla estricta para garantizar la integridad
CREATE TABLE usuarios (
id INTEGER PRIMARY KEY,
email TEXT NOT NULL,
activo INTEGER DEFAULT 1
) STRICT;
-- Sin 'STRICT', SQLite permitiría insertar "sí" en la columna 'activo'.SQL2.4. Ausencia de Gestión de Accesos (RBAC)
SQLite carece de un sistema de usuarios, roles o permisos (no soporta sentencias GRANT o REVOKE). Al ser un archivo físico, la seguridad delegada se reduce a los permisos del sistema operativo (CHMOD/CHOWN).
Si el proceso de Python tiene acceso de lectura/escritura al archivo .sqlite o .db, tiene control absoluto sobre todas las tablas. No es posible crear un acceso de “solo lectura” para un usuario específico o restringir el acceso a nivel de esquema, lo que complica su uso en aplicaciones multi-inquilino (multi-tenant) con aislamiento estricto de datos.