← 精品代码功能 · 可复用实现库

精品功能 12:关联数据批量查询(邻接表,避免 N+1)

列表页要显示每张卡的"关联数",天真做法是每张卡查一次数据库——
100 张卡就是 101 次查询。数据一多就明显变慢。

核心实现

批量 + 邻接表(第 547-560 行):

def attach_links(cards):
    """给卡片列表批量附加关联卡片 id(供列表页显示关联数)。"""
    if not cards:
        return cards
    conn = db()
    rows = conn.execute("SELECT a,b FROM links").fetchall()   # 一次拿全部关系
    conn.close()
    m = {}
    for r in rows:                       # 在内存里建无向邻接表
        m.setdefault(r["a"], set()).add(r["b"])
        m.setdefault(r["b"], set()).add(r["a"])
    for c in cards:
        c["links"] = sorted(x for x in m.get(c["id"], set()) if x != c["id"])
    return cards

单条查关联(无向关系,用 UNION 两个方向,第 538-544 行):

def links_of(cid):
    conn = db()
    rows = conn.execute(
        "SELECT b FROM links WHERE a=? UNION SELECT a FROM links WHERE b=?", (cid, cid)
    ).fetchall()
    conn.close()
    return [r[0] for r in rows]

详情页要标题而不只是 id(第 563-574 行):

def card_full(cid):
    card = card_by_id(cid)
    if not card:
        return None
    ids = [x for x in links_of(cid) if x != cid]
    card["links"] = ids
    card["link_cards"] = []
    for x in ids:
        c = card_by_id(x)
        if c:
            card["link_cards"].append({"id": x, "title": c["title"]})
    return card

设计亮点

  1. 消除 N+1:列表场景"一次查询 + 内存聚合",把 N+1 次库操作降到 1 次
  2. 无向关系用 UNION:a→b 和 b→a 是同一条,查两个方向才对
  3. 内存邻接表:dict[str, set] 是最简单的图结构,够用且快
  4. 过滤自环:if x != c["id"] 排除"自己关联自己"
  5. 列表给 id、详情给标题:不同场景返回不同粒度,避免列表页做多余查询

可复用性评估

开源化建议

对照开源

相关课程

第 15 课(结构化输出实战)