perf(pool): 添加性能计时日志,优化批量删除分批与模型解除关联查询

- 前端批量操作对话框添加 loadAllKeys/executeAction 计时日志
- 后端池账号列表接口和批量删除接口添加分阶段耗时日志
- 批量删除按数据库类型自动选择分批大小,统一前端 batch size 为 2000
- 优化 auto_disassociate 查询:先检查 unlimited key 提前返回,使用 load_only 减少字段加载
- 新增批量操作路由和自动解除关联的单元测试
This commit is contained in:
fawney19
2026-03-08 03:58:10 +08:00
parent 124c4ca403
commit 25c33846be
5 changed files with 371 additions and 37 deletions

View File

@@ -8,7 +8,7 @@ from __future__ import annotations
from typing import cast
from sqlalchemy.orm import Session, joinedload
from sqlalchemy.orm import Session, joinedload, load_only
from src.core.exceptions import InvalidRequestException, NotFoundException
from src.core.logger import logger
@@ -502,9 +502,25 @@ class GlobalModelService:
logger.warning(f"Provider {provider_id} not found for auto-disassociation")
return results
# 1. 获取 Provider 下所有活跃 Key 的 allowed_models 并集
keys = (
db.query(ProviderAPIKey)
# 1. 先快速检查是否存在“允许所有模型”的活跃 Key。
# 这种情况下无需解除任何关联,避免继续扫描整张 key 表。
has_unlimited_key = (
db.query(ProviderAPIKey.id)
.filter(
ProviderAPIKey.provider_id == provider_id,
ProviderAPIKey.is_active == True,
ProviderAPIKey.allowed_models.is_(None),
)
.limit(1)
.first()
is not None
)
if has_unlimited_key:
return results
# 2. 仅查询活跃 Key 的 allowed_models 列,避免把 api_key/auth_config 等大字段整行拉出。
allowed_model_rows = (
db.query(ProviderAPIKey.allowed_models)
.filter(
ProviderAPIKey.provider_id == provider_id,
ProviderAPIKey.is_active == True,
@@ -512,36 +528,32 @@ class GlobalModelService:
.all()
)
# 收集所有 Key 的 allowed_models 并集
# 注意allowed_models 为 null 表示允许所有模型,此时不应解除任何关联
all_allowed_models: set[str] = set()
has_unlimited_key = False # 是否存在允许所有模型的 Key
for key in keys:
if key.allowed_models is None:
# null 表示允许所有模型,直接返回不做任何解除
has_unlimited_key = True
break
if key.allowed_models:
all_allowed_models.update(key.allowed_models)
# 如果存在允许所有模型的 Key不需要解除任何关联
if has_unlimited_key:
return results
# 如果 Provider 无活跃 Key不做任何解除保留现有关联
if not keys:
if not allowed_model_rows:
return results
# 2. 获取 Provider 当前关联的所有 Model带 GlobalModel 信息)
# 收集所有 Key 的 allowed_models 并集
all_allowed_models: set[str] = set()
for (allowed_models,) in allowed_model_rows:
if isinstance(allowed_models, list) and allowed_models:
all_allowed_models.update(m for m in allowed_models if isinstance(m, str))
# 3. 获取 Provider 当前关联的所有 Model仅加载判定所需字段
models = (
db.query(Model)
.options(joinedload(Model.global_model))
.options(
load_only(Model.id, Model.provider_id, Model.global_model_id),
joinedload(Model.global_model).load_only(
GlobalModel.id,
GlobalModel.name,
GlobalModel.config,
),
)
.filter(Model.provider_id == provider_id)
.all()
)
# 3. 检查每个 Model 是否还能匹配,收集需要删除的 Model
# 4. 检查每个 Model 是否还能匹配,收集需要删除的 Model
models_to_delete: list[Model] = []
for model in models:
@@ -577,7 +589,7 @@ class GlobalModelService:
if not matched:
models_to_delete.append(model)
# 4. 批量删除不再匹配的 Model全部成功或全部失败
# 5. 批量删除不再匹配的 Model全部成功或全部失败
if models_to_delete:
try:
for model in models_to_delete: