首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >WorkBuddy 写的代码功能都对,但你敢看执行时间吗?——五个常见性能反模式

WorkBuddy 写的代码功能都对,但你敢看执行时间吗?——五个常见性能反模式

原创
作者头像
用户12475538
发布2026-05-12 11:58:19
发布2026-05-12 11:58:19
1600
举报
文章被收录于专栏:与workbuddy合作与workbuddy合作

WorkBuddy 写的代码功能都对,但你敢看执行时间吗?——五个常见性能反模式

功能正确 ≠ 性能正常。AI 写的代码有一种特殊的"慢法":不是算法选错了,是做了不该做的重复劳动。


一个加载了 30 秒的页面

WorkBuddy 帮我写了一个管理后台的"用户列表"页面。功能完美——分页、搜索、排序全有。部署到测试环境,加载 30 秒。

排查发现:每行用户记录都在循环里单独发了一次数据库查询。100 个用户 = 101 次查询。代码逻辑完全正确,只是数据库被"问候"了 101 次。

这不是"写错了"。是"用错了模式"。


反模式一:N+1 查询——循环里查数据库

现象

代码语言:python
复制
# WorkBuddy 写的典型代码
def get_users_with_orders():
    users = db.query("SELECT * FROM users LIMIT 100")
    result = []
    for user in users:
        # ⚡ 每循环一次 = 一次数据库查询
        orders = db.query(f"SELECT * FROM orders WHERE user_id = {user.id}")
        result.append({"user": user, "orders": orders})
    return result
    # 100 个用户 = 101 次查询

为什么 AI 这么写

这是最自然的思维:先拿到用户列表,然后"对于每个用户,查他的订单"。人类自然语言的逻辑就是这样的。 AI 的代码忠实地翻译了这种思维方式。

修复:JOIN 或批量查询

代码语言:python
复制
def get_users_with_orders():
    # 方案 A:JOIN(适合数据量不大的情况)
    rows = db.query("""
        SELECT u.*, o.*
        FROM users u
        LEFT JOIN orders o ON o.user_id = u.id
        WHERE u.id IN (SELECT id FROM users LIMIT 100)
    """)
    return group_by_user(rows)

    # 方案 B:先批量取 ID,再 IN 查询(适合数据量大的情况)
    users = db.query("SELECT * FROM users LIMIT 100")
    user_ids = [u.id for u in users]
    orders = db.query(
        f"SELECT * FROM orders WHERE user_id IN ({','.join(map(str, user_ids))})"
    )
    orders_by_user = group_by(orders, key="user_id")
    return [{"user": u, "orders": orders_by_user.get(u.id, [])} for u in users]

检测方法

代码语言:python
复制
# 在代码中搜索这个模式
# for ... in ...:
#     db.query / db.execute / ORM query
# 如果 query 出现在循环体内 → 大概率是 N+1

反模式二:全量加载再做分页

现象

代码语言:python
复制
# WorkBuddy 写的又一段典型代码
def list_users(page=1, per_page=20):
    all_users = db.query("SELECT * FROM users")  # ⚡ 加载了全部 10 万条
    start = (page - 1) * per_page
    end = start + per_page
    return all_users[start:end]  # 然后在内存里切片

为什么 AI 这么写

Python 的切片操作很直观:data[start:end]。AI 学会了这个模式,然后把它套在了数据库查询上——它不区分"list 切片"和"数据库查询"在性能上的天壤之别。

修复:让数据库做分页

代码语言:python
复制
def list_users(page=1, per_page=20):
    offset = (page - 1) * per_page
    # 让数据库做分页,不要全量加载
    users = db.query(
        f"SELECT * FROM users ORDER BY id LIMIT {per_page} OFFSET {offset}"
    )
    total = db.query("SELECT COUNT(*) as cnt FROM users")[0].cnt
    return {"data": users, "total": total, "page": page}

检测方法

代码语言:python
复制
# SELECT * FROM table(没有 LIMIT)
# 然后在 Python 里切片 [start:end]
# 或者用 len() 取总数(说明全量加载了)

反模式三:循环里的重复计算

现象

代码语言:python
复制
def generate_report(transactions):
    report = []
    for txn in transactions:
        # ⚡ 每条记录都重新算一遍"本月第一天"
        month_start = datetime(txn.date.year, txn.date.month, 1)

        # ⚡ 每条记录都重新查一遍汇率
        rate = get_exchange_rate(txn.currency)  # 假设有 100 种货币,但实际只有 3 种

        report.append({
            "id": txn.id,
            "amount_cny": txn.amount * rate,
            "month": month_start
        })
    return report

修复:提到循环外

代码语言:python
复制
from functools import lru_cache

@lru_cache(maxsize=10)
def get_rate_cached(currency):
    return get_exchange_rate(currency)

def generate_report(transactions):
    report = []
    # month_start 可以按交易日期分组,不用每条都算
    for txn in transactions:
        report.append({
            "id": txn.id,
            "amount_cny": txn.amount * get_rate_cached(txn.currency),
            "month": txn.date.replace(day=1)  # 更快的方式
        })
    return report

反模式四:过度使用深拷贝

现象

代码语言:python
复制
import copy

def process_items(items):
    results = []
    for item in items:
        # ⚡ 每条记录都深拷贝一次
        processed = copy.deepcopy(item)
        processed["status"] = compute_status(item)
        results.append(processed)
    return results

copy.deepcopy 是 AI 的安全毯。 它不确定修改会不会影响原数据,所以先深拷贝——反正"安全"。但深拷贝一个 1000 条记录的列表,每条记录有 50 个字段,性能成本是线性的但不小。

修复:只拷贝需要修改的层级

代码语言:python
复制
def process_items(items):
    results = []
    for item in items:
        # 浅拷贝够用(只改顶层字段)
        processed = dict(item)  # 或 item.copy()
        processed["status"] = compute_status(item)
        results.append(processed)
    return results

经验法则:如果你只改顶层字段 → 浅拷贝。如果你要改嵌套结构 → 才需要深拷贝。 AI 不懂这个区别,它默认用最安全的方式。


反模式五:在循环内打开文件/连接

现象

代码语言:python
复制
def batch_process_files(file_list):
    for filepath in file_list:
        # ⚡ 每次循环都创建新连接
        conn = create_db_connection()

        data = read_file(filepath)
        conn.execute("INSERT INTO logs VALUES (?)", (data,))

        conn.close()  # 每次循环打开+关闭

100 个文件 = 100 次数据库连接建立 + 100 次关闭。 连接的建立成本远高于查询本身。

修复:连接复用

代码语言:python
复制
def batch_process_files(file_list):
    with create_db_connection() as conn:  # 一个连接处理所有文件
        for filepath in file_list:
            data = read_file(filepath)
            conn.execute("INSERT INTO logs VALUES (?)", (data,))
            # 批量提交,不要每条 commit
        conn.commit()  # 一次性提交

检测方法

代码语言:python
复制
# 在 for 循环内搜索:
# - create_connection / connect / open
# - .close()
# 如果 for 循环内有连接打开 → 反模式

五个反模式速查

代码语言:markdown
复制
| 反模式 | 症状 | 修复 |
|--------|------|------|
| N+1 查询 | 循环内发 DB 请求 | JOIN 或 IN 批量查询 |
| 全量加载分页 | SELECT * 无 LIMIT | LIMIT + OFFSET |
| 循环内重复计算 | 每条记录重算同一值 | 提到循环外 / 缓存 |
| 过度深拷贝 | 到处 copy.deepcopy | 浅拷贝 / 不拷贝 |
| 循环内开连接 | 每次循环建新连接 | 一个连接复用 |

让 WorkBuddy 帮你检查

比起手动排查,更快的方式:让 WorkBuddy 自己去检查它写的代码。

代码语言:python
复制
你:帮我检查这段代码的性能反模式,重点看:
   1. 有没有循环里的数据库查询
   2. 有没有全量加载再分页
   3. 有没有可以提到循环外的重复计算

[粘贴代码]

WorkBuddy:[逐条指出问题 + 给出修复建议]

这就是愉快协作的一部分——你不用当老师教它怎么避免反模式,你当审查者,让它自查。 它很擅长找出这类模式(因为见过太多),只是在写的时候就忘了。


本文基于与 WorkBuddy 的协作经验撰写。你见过最离谱的 AI 性能 bug 是什么?评论区来比谁更慢。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • WorkBuddy 写的代码功能都对,但你敢看执行时间吗?——五个常见性能反模式
    • 一个加载了 30 秒的页面
    • 反模式一:N+1 查询——循环里查数据库
      • 现象
      • 为什么 AI 这么写
      • 修复:JOIN 或批量查询
      • 检测方法
    • 反模式二:全量加载再做分页
      • 现象
      • 为什么 AI 这么写
      • 修复:让数据库做分页
      • 检测方法
    • 反模式三:循环里的重复计算
      • 现象
      • 修复:提到循环外
    • 反模式四:过度使用深拷贝
      • 现象
      • 修复:只拷贝需要修改的层级
    • 反模式五:在循环内打开文件/连接
      • 现象
      • 修复:连接复用
      • 检测方法
    • 五个反模式速查
    • 让 WorkBuddy 帮你检查
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档