Skip to content

perf: 首页已分配作业查询合并为一次,active id 在 Python 中派生 - #66

Merged
XiaoCow666 merged 1 commit into
XiaoCow666:mainfrom
linxi123-A:perf/home-assigned-ids-single-query
Sep 22, 2026
Merged

XiaoCow666 merged 1 commit into
XiaoCow666:mainfrom
linxi123-A:perf/home-assigned-ids-single-query

Conversation

@linxi123-A

Copy link
Copy Markdown
Contributor

背景

阶段十要求"用一次测量验证一个小优化是否有效"。选择学生首页(/home )这条核心路径中一处明确的冗余查询作为优化对象,先记录基线,再做一处低风险改动,重复同一测量,用数据确认效果。

优化点

routes/main.py 的home 视图中,对同一批已分配作业执行了 两次独立查询 :

Python

1
2
3
4
5
6
7

`# 第一次:取全部已分配作业 id
all_assigned_ids = [row[0] for row in assigned_assignments_query.with_entities(Assignment.id).all()]

第二次:在同一 query 上加 due_date 过滤,再取一次 id

active_assignment_ids = [row[0] for row in assigned_assignments_query.filter(
(Assignment.due_date >= now) | (Assignment.due_date.is_(None))
).with_entities(Assignment.id).all()]`

active_assignment_ids 是all_assigned_ids 的子集,只需要截止日期这个额外字段就能在内存中派生,不必再走一次数据库 round-trip。

改动(一处,routes/main.py)

一次查出(id, due_date) ,全部 id 与未截止 id 都在 Python 中派生:

Python

1
2
3
4
5
6
7
8

assigned_rows = assigned_assignments_query.with_entities( Assignment.id, Assignment.due_date, ).all() all_assigned_ids = [row[0] for row in assigned_rows] active_assignment_ids = [ row[0] for row in assigned_rows if row[1] is None or row[1] >= now ]

下游使用完全不变:assignments_count = len(all_assigned_ids) 、active_assignments_count = len(active_assignment_ids) 、submitted_assignment_ids (Submission.assignment_id.in_(all_assigned_ids) )、average_score_query (Submission.assignment_id.in_(all_assigned_ids) )。

测量(基线 vs 改动后)

测量脚本用隔离的测试 SQLite 库(tests.demo_test_utils.create_test_app ),播种 200 条 Assignment(混合已截止 / 未截止 / 无截止日期三种状态),用 SQLAlchemybefore_cursor_execute 事件统计 SELECT 次数,用time.perf_counter 计时,每轮取 50 次调用的平均。

指标 基线(两次查询) 改动后(一次查询) 变化 查询次数 / 调用 2 1 −50% 平均耗时 0.625 ms 0.400 ms −36% 最小耗时 0.541 ms 0.347 ms −36%

正确性:测量脚本内断言set(baseline_all_ids) == set(optimized_all_ids) 且set(baseline_active_ids) == set(optimized_active_ids) ,通过——两种实现返回的 id 集合完全一致。

测量命令(临时脚本_measure_home_query.py ,测量完成后已删除,未进入仓库):

Bash

运行

1

python _measure_home_query.py

回归验证

Bash

运行

1

pytest tests/test_demo_experience.py tests/test_demo_guided_learning.py tests/test_feedback_center.py -q

结果: 15 passed (覆盖 demo 种子幂等、引导学习全流程、反馈中心;这些路径均经过同库查询与首页渲染相关逻辑)。

没有优化的部分

  • 首页其余查询保持原样,未在本次改动范围:
    • submitted_assignment_ids (db.session.query(Submission.assignment_id).filter(...).distinct() )
    • average_score_query (func.avg(Submission.score) )
    • recent_assignments 、recent_sessions +latest_session_activity 等
  • 改动只减少一次数据库往返,不改变任何返回值、不改变下游逻辑。

回退

单提交、改动集中在home 函数内一个查询块,revert 即可。

@XiaoCow666 XiaoCow666 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeSense 自动评审

核心优化已完成:将同一批已分配作业的两次查询合并为一次,并在 Python 中派生有效作业 ID。现有 diff 未发现会导致安全风险、数据损坏、明显回归或无法运行的阻塞问题。

合并后可以继续改进的地方

  • 有效作业筛选从数据库表达式改为 Python datetime 比较,未来若数据库返回值与 now 的时区或类型不一致,可能引发兼容性问题;当前提供的测量断言和回归结果未显示该问题。
  • PR 描述中的临时测量脚本已删除,后续若需复现性能数据需要重新准备测量脚本。

已有验证信息

  • PR 描述报告隔离 SQLite 测量中查询次数由每次 2 次降为 1 次,平均耗时由 0.625 ms 降至 0.400 ms。
  • PR 描述报告测量脚本已断言优化前后全部作业 ID 和有效作业 ID 集合一致。
  • PR 描述报告回归命令 pytest tests/test_demo_experience.py tests/test_demo_guided_learning.py tests/test_feedback_center.py -q 结果为 15 passed。

评审事件:7995cbc0-b638-11f1-8859-ce8747d84055

@XiaoCow666
XiaoCow666 merged commit 949ba90 into XiaoCow666:main Sep 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants