From fd1c1a5abcd5f06ec313039ad63bd08c7b8a627e Mon Sep 17 00:00:00 2001 From: guke Date: Sat, 18 Jul 2026 18:31:15 +0800 Subject: [PATCH] =?UTF-8?q?perf(analytics):=20analytics=5Fevent=20?= =?UTF-8?q?=E6=B4=BB=E8=B7=83=E5=8F=A3=E5=BE=84=E5=A4=8D=E5=90=88=E7=B4=A2?= =?UTF-8?q?=E5=BC=95=20(event,page,user=5Fid,created=5Fat)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit active_event_condition 按 (event=show & page=home) ∪ 比价 ∪ 领券 过滤后 group by user_id、 max(created_at),是 worker 清零/预警 + admin 最近活跃的热点聚合;page 原无索引、show 又高频。 加覆盖索引 ix_analytics_event_active 让该聚合走 index-only。 ⚠️ 分支迁移树既有多头(135e79414fd0 与 phone_rebind_log 同从 comparison_llm_cost 分叉, `alembic upgrade head` 会多头报错)——既有问题、与本次无关。本迁移挂在 135e79414fd0 一侧, dev 用 `alembic upgrade analytics_active_idx` 应用;集成 main 时需 alembic merge 合并 phone_rebind_log 头。 Co-Authored-By: Claude Opus 4.8 (1M context) --- ...ytics_active_idx_active_composite_index.py | 36 +++++++++++++++++++ app/models/analytics_event.py | 8 ++++- 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 alembic/versions/analytics_active_idx_active_composite_index.py diff --git a/alembic/versions/analytics_active_idx_active_composite_index.py b/alembic/versions/analytics_active_idx_active_composite_index.py new file mode 100644 index 0000000..8cdaa5c --- /dev/null +++ b/alembic/versions/analytics_active_idx_active_composite_index.py @@ -0,0 +1,36 @@ +"""analytics_event 活跃口径复合索引 + +Revision ID: analytics_active_idx +Revises: 135e79414fd0 +Create Date: 2026-07-18 17:35:00.000000 + +给 analytics_event 加活跃口径热点复合索引 (event, page, user_id, created_at): +activity.active_event_condition 按 (event=show & page=home) ∪ 比价 ∪ 领券 过滤后 +group by user_id、max(created_at)。覆盖索引让该聚合走 index-only,避免高频 show 事件全表扫。 + +⚠️ 本分支迁移树有**既有多头**:135e79414fd0(不活跃两表)与 phone_rebind_log 同从 +comparison_llm_cost 分叉,`alembic upgrade head` 会多头报错。本迁移挂在 135e79414fd0 +一侧;集成到 main 时需 `alembic merge` 合并 phone_rebind_log 那个头(与本迁移无关的既有问题)。 +""" +from typing import Sequence, Union + +from alembic import op + +# revision identifiers, used by Alembic. +revision: str = "analytics_active_idx" +down_revision: Union[str, Sequence[str], None] = "135e79414fd0" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.create_index( + "ix_analytics_event_active", + "analytics_event", + ["event", "page", "user_id", "created_at"], + unique=False, + ) + + +def downgrade() -> None: + op.drop_index("ix_analytics_event_active", table_name="analytics_event") diff --git a/app/models/analytics_event.py b/app/models/analytics_event.py index 63110c3..21f03c5 100644 --- a/app/models/analytics_event.py +++ b/app/models/analytics_event.py @@ -15,7 +15,7 @@ from __future__ import annotations from datetime import datetime -from sqlalchemy import JSON, BigInteger, DateTime, Integer, String, func +from sqlalchemy import JSON, BigInteger, DateTime, Index, Integer, String, func from sqlalchemy.orm import Mapped, mapped_column from app.db.base import Base @@ -23,6 +23,12 @@ from app.db.base import Base class AnalyticsEvent(Base): __tablename__ = "analytics_event" + __table_args__ = ( + # 活跃口径聚合热点(activity.active_event_condition + last_active_subqueries): + # 按 (event,page) 过滤 首页可见(show/home)∪比价∪领券,再 group by user_id 取 + # max(created_at)。覆盖索引 → 该聚合走 index-only,避免高频 show 事件全表扫。 + Index("ix_analytics_event_active", "event", "page", "user_id", "created_at"), + ) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)