From 23159c2ab9723f3bbdf8aa3239b2a73064a03c14 Mon Sep 17 00:00:00 2001 From: decent-engineer-decent-datascientist Date: Thu, 19 Jun 2025 17:56:25 -0500 Subject: [PATCH 1/3] added basic indexing and a migration plan --- backend/open_webui/models/chats.py | 16 +++++++++++++++- backend/open_webui/models/functions.py | 6 +++++- backend/open_webui/models/tags.py | 7 ++++--- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index 0ac53a023..71e7b34bf 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -9,7 +9,7 @@ from open_webui.models.tags import TagModel, Tag, Tags from open_webui.env import SRC_LOG_LEVELS from pydantic import BaseModel, ConfigDict -from sqlalchemy import BigInteger, Boolean, Column, String, Text, JSON +from sqlalchemy import BigInteger, Boolean, Column, String, Text, JSON, Index from sqlalchemy import or_, func, select, and_, text from sqlalchemy.sql import exists @@ -39,6 +39,20 @@ class Chat(Base): meta = Column(JSON, server_default="{}") folder_id = Column(Text, nullable=True) + __table_args__ = ( + # Performance indexes for common queries + # WHERE folder_id = ... + Index('folder_id_idx', 'folder_id'), + # WHERE user_id = ... AND pinned = ... + Index('user_id_pinned_idx', 'user_id', 'pinned'), + # WHERE user_id = ... AND archived = ... + Index('user_id_archived_idx', 'user_id', 'archived'), + # WHERE user_id = ... ORDER BY updated_at DESC + Index('updated_at_user_id_idx', 'updated_at', 'user_id'), + # WHERE folder_id = ... AND user_id = ... + Index('folder_id_user_id_idx', 'folder_id', 'user_id'), + ) + class ChatModel(BaseModel): model_config = ConfigDict(from_attributes=True) diff --git a/backend/open_webui/models/functions.py b/backend/open_webui/models/functions.py index e98771fa0..af2311319 100644 --- a/backend/open_webui/models/functions.py +++ b/backend/open_webui/models/functions.py @@ -6,7 +6,7 @@ from open_webui.internal.db import Base, JSONField, get_db from open_webui.models.users import Users from open_webui.env import SRC_LOG_LEVELS from pydantic import BaseModel, ConfigDict -from sqlalchemy import BigInteger, Boolean, Column, String, Text +from sqlalchemy import BigInteger, Boolean, Column, String, Text, Index log = logging.getLogger(__name__) log.setLevel(SRC_LOG_LEVELS["MODELS"]) @@ -31,6 +31,10 @@ class Function(Base): updated_at = Column(BigInteger) created_at = Column(BigInteger) + __table_args__ = ( + Index('is_global_idx', 'is_global'), + ) + class FunctionMeta(BaseModel): description: Optional[str] = None diff --git a/backend/open_webui/models/tags.py b/backend/open_webui/models/tags.py index 279dc624d..46e412d81 100644 --- a/backend/open_webui/models/tags.py +++ b/backend/open_webui/models/tags.py @@ -8,7 +8,7 @@ from open_webui.internal.db import Base, get_db from open_webui.env import SRC_LOG_LEVELS from pydantic import BaseModel, ConfigDict -from sqlalchemy import BigInteger, Column, String, JSON, PrimaryKeyConstraint +from sqlalchemy import BigInteger, Column, String, JSON, PrimaryKeyConstraint, Index log = logging.getLogger(__name__) log.setLevel(SRC_LOG_LEVELS["MODELS"]) @@ -24,8 +24,9 @@ class Tag(Base): user_id = Column(String) meta = Column(JSON, nullable=True) - # Unique constraint ensuring (id, user_id) is unique, not just the `id` column - __table_args__ = (PrimaryKeyConstraint("id", "user_id", name="pk_id_user_id"),) + __table_args__ = ( + Index('user_id_idx', 'user_id'), + ) class TagModel(BaseModel): From 888a98c090884363b0ac976d1e0842d038aee66b Mon Sep 17 00:00:00 2001 From: decent-engineer-decent-datascientist Date: Thu, 19 Jun 2025 18:05:10 -0500 Subject: [PATCH 2/3] added migration plan --- .../20250619_add_indexes_for_performance.py | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 backend/open_webui/migrations/versions/20250619_add_indexes_for_performance.py diff --git a/backend/open_webui/migrations/versions/20250619_add_indexes_for_performance.py b/backend/open_webui/migrations/versions/20250619_add_indexes_for_performance.py new file mode 100644 index 000000000..8688474f1 --- /dev/null +++ b/backend/open_webui/migrations/versions/20250619_add_indexes_for_performance.py @@ -0,0 +1,57 @@ +"""Add performance indexes to chat, tag, and function tables + +--- +Database Indexing & Migration Instructions +------------------------------------------ +Open-WebUI now automatically creates indexes on key columns in the `chat`, `tag`, and `function` tables for improved performance with SQLite and PostgreSQL. + +**For existing installations:** +Apply this migration to add the new indexes to your database: + + alembic upgrade head + +This will significantly speed up filtering, sorting, and joining operations as your data grows. +--- + +Revision ID: 20250619_add_indexes +Revises: +Create Date: 2025-06-19 + +""" + +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = '20250619_add_indexes' +down_revision = None +branch_labels = None +depends_on = None + +def upgrade(): + # Chat table indexes + op.create_index('folder_id_idx', 'chat', ['folder_id']) + op.create_index('user_id_pinned_idx', 'chat', ['user_id', 'pinned']) + op.create_index('user_id_archived_idx', 'chat', ['user_id', 'archived']) + op.create_index('updated_at_user_id_idx', 'chat', ['updated_at', 'user_id']) + op.create_index('folder_id_user_id_idx', 'chat', ['folder_id', 'user_id']) + + # Tag table index + op.create_index('user_id_idx', 'tag', ['user_id']) + + # Function table index + op.create_index('is_global_idx', 'function', ['is_global']) + +def downgrade(): + # Chat table indexes + op.drop_index('folder_id_idx', table_name='chat') + op.drop_index('user_id_pinned_idx', table_name='chat') + op.drop_index('user_id_archived_idx', table_name='chat') + op.drop_index('updated_at_user_id_idx', table_name='chat') + op.drop_index('folder_id_user_id_idx', table_name='chat') + + # Tag table index + op.drop_index('user_id_idx', table_name='tag') + + # Function table index + op.drop_index('is_global_idx', table_name='function') \ No newline at end of file From f96b8ecb5b64ec9807bc75f68bd905f97309a979 Mon Sep 17 00:00:00 2001 From: decent-engineer-decent-datascientist Date: Thu, 19 Jun 2025 18:05:22 -0500 Subject: [PATCH 3/3] added the PK on tag back, whoops --- backend/open_webui/models/tags.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/open_webui/models/tags.py b/backend/open_webui/models/tags.py index 46e412d81..768e94f85 100644 --- a/backend/open_webui/models/tags.py +++ b/backend/open_webui/models/tags.py @@ -25,6 +25,7 @@ class Tag(Base): meta = Column(JSON, nullable=True) __table_args__ = ( + PrimaryKeyConstraint("id", "user_id", name="pk_id_user_id"), Index('user_id_idx', 'user_id'), )