Skip to content

Commit 187f93f

Browse files
committed
perf: optimize SQLite WAL connection pragmas
1 parent c039c35 commit 187f93f

1 file changed

Lines changed: 30 additions & 18 deletions

File tree

  • backend/open_webui/internal

backend/open_webui/internal/db.py

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,32 @@ def _make_async_url(url: str) -> str:
108108
# Alembic, peewee migration, health checks)
109109
# ============================================================
110110

111+
# Shared SQLite connection/close handlers, used by both sync and async engines
112+
def _sqlite_on_connect(dbapi_connection, connection_record):
113+
cursor = dbapi_connection.cursor()
114+
if DATABASE_ENABLE_SQLITE_WAL:
115+
cursor.execute('PRAGMA journal_mode=WAL')
116+
# synchronous=NORMAL is safe with WAL: durable on app crash, may roll back
117+
# last transactions on OS crash or power loss; acceptable for most web apps.
118+
cursor.execute('PRAGMA synchronous=NORMAL')
119+
cursor.execute('PRAGMA journal_size_limit=67108864') # Cap WAL file at 64 MB
120+
cursor.execute('PRAGMA cache_size=-32768') # 32 MB page cache
121+
cursor.execute('PRAGMA temp_store=MEMORY')
122+
cursor.execute('PRAGMA busy_timeout=5000') # Retry up to 5 s on lock contention
123+
else:
124+
cursor.execute('PRAGMA journal_mode=DELETE')
125+
cursor.close()
126+
127+
128+
def _sqlite_on_checkin(dbapi_connection, connection_record):
129+
if dbapi_connection is None:
130+
return
131+
cursor = dbapi_connection.cursor()
132+
cursor.execute('PRAGMA analysis_limit=400') # Bound analysis work per checkin
133+
cursor.execute('PRAGMA optimize') # Update query planner statistics
134+
cursor.close()
135+
136+
111137
# Handle SQLCipher URLs
112138
if SQLALCHEMY_DATABASE_URL.startswith('sqlite+sqlcipher://'):
113139
database_password = os.environ.get('DATABASE_PASSWORD')
@@ -154,16 +180,8 @@ def create_sqlcipher_connection():
154180

155181
elif 'sqlite' in SQLALCHEMY_DATABASE_URL:
156182
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={'check_same_thread': False})
157-
158-
def on_connect(dbapi_connection, connection_record):
159-
cursor = dbapi_connection.cursor()
160-
if DATABASE_ENABLE_SQLITE_WAL:
161-
cursor.execute('PRAGMA journal_mode=WAL')
162-
else:
163-
cursor.execute('PRAGMA journal_mode=DELETE')
164-
cursor.close()
165-
166-
event.listen(engine, 'connect', on_connect)
183+
event.listen(engine, 'connect', _sqlite_on_connect)
184+
event.listen(engine, 'checkin', _sqlite_on_checkin)
167185
else:
168186
if isinstance(DATABASE_POOL_SIZE, int):
169187
if DATABASE_POOL_SIZE > 0:
@@ -212,14 +230,8 @@ def get_session():
212230
ASYNC_SQLALCHEMY_DATABASE_URL,
213231
connect_args={'check_same_thread': False},
214232
)
215-
216-
if DATABASE_ENABLE_SQLITE_WAL:
217-
218-
@event.listens_for(async_engine.sync_engine, 'connect')
219-
def _set_sqlite_wal(dbapi_connection, connection_record):
220-
cursor = dbapi_connection.cursor()
221-
cursor.execute('PRAGMA journal_mode=WAL')
222-
cursor.close()
233+
event.listen(async_engine.sync_engine, 'connect', _sqlite_on_connect)
234+
event.listen(async_engine.sync_engine, 'checkin', _sqlite_on_checkin)
223235
else:
224236
if isinstance(DATABASE_POOL_SIZE, int):
225237
if DATABASE_POOL_SIZE > 0:

0 commit comments

Comments
 (0)