Skip to content

Commit ec714dc

Browse files
committed
perf(db): tune SQLite connection pragmas for small VPS
- synchronous=NORMAL: WAL keeps committed data safe against app crashes while skipping an fsync per commit. - temp_store=MEMORY: temp tables and sorts stay in RAM. - cache_size=-8000: cap page cache at ~8MB. Tortoise's SqliteClient applies every non-file_path credential as a PRAGMA on its single connection, so this is the only place that needs changing.
1 parent 3d2c8ec commit ec714dc

2 files changed

Lines changed: 61 additions & 0 deletions

File tree

‎core/database.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@ def get_db_config() -> dict:
2525
"journal_mode": "WAL",
2626
"busy_timeout": 10000,
2727
"foreign_keys": "ON",
28+
# 小内存 VPS 下的 IOPS 与内存折中。Tortoise 的 SqliteClient 会把
29+
# credentials 中 file_path 以外的键逐条执行成 PRAGMA,且 SQLite
30+
# 后端只维持单条连接,因此这些设置在进程生命周期内全局生效。
31+
# synchronous=NORMAL:WAL 下应用崩溃不丢已提交事务,
32+
# 仅 OS/断电可能丢最后若干事务,省去每次提交的 fsync。
33+
# temp_store=MEMORY:临时表与排序走内存,小库收益明显;
34+
# 后台大排序的内存峰值需在压测中关注。
35+
# cache_size=-8000:page cache 上限约 8MB(负数单位为 KiB)。
36+
"synchronous": "NORMAL",
37+
"temp_store": "MEMORY",
38+
"cache_size": -8000,
2839
},
2940
}
3041
},

‎tests/test_sqlite_pragmas.py‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
"""SQLite 连接 PRAGMA 生效性验证。
2+
3+
不 mock 配置字典,而是用 get_db_config() 真起一个文件库读取 PRAGMA——
4+
Tortoise 的 SqliteClient 在 create_connection() 时逐条执行 credentials 中的
5+
PRAGMA,只有真实连接才能验证这一点。
6+
"""
7+
import pytest
8+
from tortoise import Tortoise
9+
10+
import core.database as database
11+
from tests.helpers import close_db
12+
13+
14+
@pytest.fixture
15+
async def file_db(tmp_path, monkeypatch):
16+
monkeypatch.setattr(database, "_DB_FILE", str(tmp_path / "pragma.db"))
17+
if Tortoise._inited:
18+
await Tortoise.close_connections()
19+
await Tortoise.init(config=database.get_db_config())
20+
try:
21+
yield Tortoise.get_connection("default")
22+
finally:
23+
await close_db()
24+
25+
26+
async def _pragma(conn, statement: str):
27+
rows = await conn.execute_query_dict(statement)
28+
return next(iter(rows[0].values()))
29+
30+
31+
@pytest.mark.asyncio
32+
class TestSqlitePragmas:
33+
async def test_wal_and_busy_timeout_kept(self, file_db):
34+
assert str(await _pragma(file_db, "PRAGMA journal_mode")).lower() == "wal"
35+
assert await _pragma(file_db, "PRAGMA busy_timeout") == 10000
36+
37+
async def test_synchronous_normal(self, file_db):
38+
# 1 = NORMAL(WAL 下省 fsync),2 = FULL
39+
assert await _pragma(file_db, "PRAGMA synchronous") == 1
40+
41+
async def test_temp_store_memory(self, file_db):
42+
# 0 = DEFAULT,1 = FILE,2 = MEMORY
43+
assert await _pragma(file_db, "PRAGMA temp_store") == 2
44+
45+
async def test_cache_size_8mb(self, file_db):
46+
# 负值单位为 KiB
47+
assert await _pragma(file_db, "PRAGMA cache_size") == -8000
48+
49+
async def test_foreign_keys_on(self, file_db):
50+
assert await _pragma(file_db, "PRAGMA foreign_keys") == 1

0 commit comments

Comments
 (0)