Django SQLite 生产环境配置指南
默认的 SQLite 配置并不适合在生产环境中运行 Django 应用。SQLite 开箱即用时针对嵌入式低并发系统进行了优化,这与 Django 应用的需求恰恰相反。
通过调整一些设置可以提高并发性能。具体操作取决于您使用的 Django 版本。
⚠️ 警告:如果在网络文件系统(如 PythonAnywhere 等托管商常用的 NFS)上使用 PRAGMA journal_mode=WAL; 设置,可能会损坏数据库。如果不确定使用的文件存储类型,请勿启用此设置。在生产环境中使用 SQLite 前,请务必了解 SQLite 的潜在问题。
Django 5.1 或更新版本
在 Django 5.1 中,可以直接在 settings.py 中进行所有必要的更改:
# yourproject/settings.py
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"OPTIONS": {
"transaction_mode": "IMMEDIATE",
"timeout": 5, # 秒
"init_command": """
PRAGMA journal_mode=WAL;
PRAGMA synchronous=NORMAL;
PRAGMA mmap_size = 134217728;
PRAGMA journal_size_limit = 27103364;
PRAGMA cache_size=2000;
""",
},
}
}
- 注意:无需指定
PRAGMA foreign_keys = ON,因为 Django 默认会设置。
- 也无需使用
PRAGMA busy_timeout,通过设置 timeout 数据库选项可达到相同效果。
Django 5.0、4.2 或更早版本
1. 启用 WAL 日志模式
最具影响力的更改是启用 WAL(Write-Ahead Logging)日志模式。如果不启用 WAL,每个写入请求都会阻塞读取,反之亦然,这会严重影响吞吐量。
启用 WAL 模式没有真正的缺点,可通过以下命令对数据库执行一次(设置将持久生效):
sqlite3 db.sqlite3 'PRAGMA journal_mode=WAL;'
2. 使用 IMMEDIATE 事务
使用 IMMEDIATE 事务并非为了提升性能(在事务运行时甚至会略微降低性能),但可以避免意外的“database is locked”错误,因此值得启用。
需要创建自定义数据库引擎:
# yourproject/sqlite3/base.py
from django.db.backends.sqlite3 import base
class DatabaseWrapper(base.DatabaseWrapper):
def _start_transaction_under_autocommit(self):
# 立即获取写锁以进行事务
self.cursor().execute("BEGIN IMMEDIATE")
然后在 settings.py 中使用此自定义引擎:
# yourproject/settings.py
DATABASES = {
"default": {
"ENGINE": "yourproject.sqlite3", # <-- 使用自定义引擎
"NAME": BASE_DIR / "db.sqlite3",
}
}
3. 微调 SQLite 设置
以下是一组可提升性能的 SQLite 设置,这些设置也是 Rails 7.1 的默认值,可作为良好的起点。您可以根据应用需求调整 mmap_size、journal_size_limit 和 cache_size:
# yourproject/sqlite3/base.py
from sqlite3 import dbapi2 as Database
from django.db.backends.sqlite3 import base
from django.db.backends.sqlite3._functions import register as register_functions
from django.utils.asyncio import async_unsafe
class DatabaseWrapper(base.DatabaseWrapper):
def _start_transaction_under_autocommit(self):
self.cursor().execute("BEGIN IMMEDIATE")
@async_unsafe
def get_new_connection(self, conn_params):
conn = Database.connect(**conn_params)
register_functions(conn)
conn.execute("PRAGMA foreign_keys = ON")
conn.execute("PRAGMA legacy_alter_table = OFF")
conn.execute("PRAGMA journal_mode = WAL")
conn.execute("PRAGMA synchronous = NORMAL")
conn.execute("PRAGMA mmap_size = 134217728")
conn.execute("PRAGMA journal_size_limit = 27103364")
conn.execute("PRAGMA cache_size = 2000")
return conn
结论
完成这些配置后,您的 SQLite 数据库将能够处理大多数中小型网站通常面临的负载,前提是您的使用场景并非写入密集型。