feat(db): replace deferred unique constraints with partial unique indexes for LLM model configs

Replace deferred UniqueConstraints with partial unique indexes for user and group default configurations in the LLM model configs table. This change improves performance and ensures at most one default config per user/group while maintaining data integrity. The migration script has been updated accordingly to create and drop the new indexes.
This commit is contained in:
YueGuobin 2026-03-03 17:57:32 +08:00
parent d42fff49a5
commit fc7275878e
3 changed files with 23 additions and 22 deletions

View File

@ -15,7 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from sqlalchemy import Column, Boolean, ForeignKey, CheckConstraint, UniqueConstraint, Index, Integer, String
from sqlalchemy import Column, Boolean, ForeignKey, CheckConstraint, Index, Integer, String, text
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import relationship
@ -65,14 +65,12 @@ class LLMModelConfig(BaseTable):
"model_type IN ('text', 'vision', 'stt', 'tts', 'multimodal', 'embedding', 'reranking', 'other')",
name="valid_model_type_check"
),
# Each user can have at most one default config
UniqueConstraint("user_id", "is_default", name="unique_user_default",
deferrable=True, initially="deferred",
postgresql_where="is_default = TRUE AND user_id IS NOT NULL"),
# Each group can have at most one default config
UniqueConstraint("group_id", "is_default", name="unique_group_default",
deferrable=True, initially="deferred",
postgresql_where="is_default = TRUE AND group_id IS NOT NULL"),
# Each user can have at most one default config (partial unique index)
Index("unique_user_default", "user_id", unique=True,
postgresql_where=text("is_default = TRUE AND user_id IS NOT NULL")),
# Each group can have at most one default config (partial unique index)
Index("unique_group_default", "group_id", unique=True,
postgresql_where=text("is_default = TRUE AND group_id IS NOT NULL")),
# Indexes for efficient queries
Index("idx_llm_model_configs_user_id", "user_id"),
Index("idx_llm_model_configs_group_id", "group_id"),

View File

@ -54,18 +54,6 @@ def upgrade() -> None:
"model_type IN ('text', 'vision', 'stt', 'tts', 'multimodal', 'embedding', 'reranking', 'other')",
name='valid_model_type_check'
),
sa.UniqueConstraint(
'user_id', 'is_default',
name='unique_user_default',
deferrable=True, initially='deferred',
postgresql_where=sa.text("is_default = TRUE AND user_id IS NOT NULL")
),
sa.UniqueConstraint(
'group_id', 'is_default',
name='unique_group_default',
deferrable=True, initially='deferred',
postgresql_where=sa.text("is_default = TRUE AND group_id IS NOT NULL")
),
)
# Create indexes for efficient queries
@ -74,6 +62,20 @@ def upgrade() -> None:
op.create_index('idx_llm_model_configs_model_type', 'llm_model_configs', ['model_type'])
op.create_index('idx_llm_model_configs_config', 'llm_model_configs', ['config'], postgresql_using='gin')
# Create partial unique indexes for default configs
# Each user can have at most one default config
op.execute("""
CREATE UNIQUE INDEX unique_user_default
ON llm_model_configs (user_id)
WHERE is_default = TRUE AND user_id IS NOT NULL
""")
# Each group can have at most one default config
op.execute("""
CREATE UNIQUE INDEX unique_group_default
ON llm_model_configs (group_id)
WHERE is_default = TRUE AND group_id IS NOT NULL
""")
def downgrade() -> None:
# Drop indexes
@ -81,6 +83,8 @@ def downgrade() -> None:
op.drop_index('idx_llm_model_configs_model_type', table_name='llm_model_configs')
op.drop_index('idx_llm_model_configs_group_id', table_name='llm_model_configs')
op.drop_index('idx_llm_model_configs_user_id', table_name='llm_model_configs')
op.drop_index('unique_user_default', table_name='llm_model_configs')
op.drop_index('unique_group_default', table_name='llm_model_configs')
# Drop table
op.drop_table('llm_model_configs')

View File

@ -35,7 +35,6 @@ from .controller.llm_model_configs import (
LLMModelConfigCreate,
LLMModelConfigUpdate,
LLMModelConfigResponse,
LLMModelConfigListResponse,
LLMModelConfigWithSource,
LLMModelConfigInheritedResponse
)