功能正确 ≠ 性能正常。AI 写的代码有一种特殊的"慢法":不是算法选错了,是做了不该做的重复劳动。
WorkBuddy 帮我写了一个管理后台的"用户列表"页面。功能完美——分页、搜索、排序全有。部署到测试环境,加载 30 秒。
排查发现:每行用户记录都在循环里单独发了一次数据库查询。100 个用户 = 101 次查询。代码逻辑完全正确,只是数据库被"问候"了 101 次。
这不是"写错了"。是"用错了模式"。
# 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 的代码忠实地翻译了这种思维方式。
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]# 在代码中搜索这个模式
# for ... in ...:
# db.query / db.execute / ORM query
# 如果 query 出现在循环体内 → 大概率是 N+1# 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] # 然后在内存里切片Python 的切片操作很直观:data[start:end]。AI 学会了这个模式,然后把它套在了数据库查询上——它不区分"list 切片"和"数据库查询"在性能上的天壤之别。
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}# SELECT * FROM table(没有 LIMIT)
# 然后在 Python 里切片 [start:end]
# 或者用 len() 取总数(说明全量加载了)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 reportfrom 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 reportimport copy
def process_items(items):
results = []
for item in items:
# ⚡ 每条记录都深拷贝一次
processed = copy.deepcopy(item)
processed["status"] = compute_status(item)
results.append(processed)
return resultscopy.deepcopy 是 AI 的安全毯。 它不确定修改会不会影响原数据,所以先深拷贝——反正"安全"。但深拷贝一个 1000 条记录的列表,每条记录有 50 个字段,性能成本是线性的但不小。
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 不懂这个区别,它默认用最安全的方式。
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 次关闭。 连接的建立成本远高于查询本身。
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() # 一次性提交# 在 for 循环内搜索:
# - create_connection / connect / open
# - .close()
# 如果 for 循环内有连接打开 → 反模式| 反模式 | 症状 | 修复 |
|--------|------|------|
| N+1 查询 | 循环内发 DB 请求 | JOIN 或 IN 批量查询 |
| 全量加载分页 | SELECT * 无 LIMIT | LIMIT + OFFSET |
| 循环内重复计算 | 每条记录重算同一值 | 提到循环外 / 缓存 |
| 过度深拷贝 | 到处 copy.deepcopy | 浅拷贝 / 不拷贝 |
| 循环内开连接 | 每次循环建新连接 | 一个连接复用 |比起手动排查,更快的方式:让 WorkBuddy 自己去检查它写的代码。
你:帮我检查这段代码的性能反模式,重点看:
1. 有没有循环里的数据库查询
2. 有没有全量加载再分页
3. 有没有可以提到循环外的重复计算
[粘贴代码]
WorkBuddy:[逐条指出问题 + 给出修复建议]这就是愉快协作的一部分——你不用当老师教它怎么避免反模式,你当审查者,让它自查。 它很擅长找出这类模式(因为见过太多),只是在写的时候就忘了。
本文基于与 WorkBuddy 的协作经验撰写。你见过最离谱的 AI 性能 bug 是什么?评论区来比谁更慢。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。