很多人学编程时,一上来就被塞了各种ORM——比如Django的models、Rails的ActiveRecord,或者Java里的Hibernate。时间久了就产生一种错觉:操作数据库就得靠ORM,手写SQL是上个世纪的事。可现实是,很多项目里,直接写SQL不仅可行,反而更高效。
ORM不是万能的
我见过一个后台系统,查个订单列表用了三层关联,结果页面加载要4秒。打开日志一看,ORM生成了七八条查询,还全是N+1问题。改成一条JOIN的SQL后,响应时间压到300毫秒。不是ORM不好,而是它太“聪明”了,有时候聪明反被聪明误。
复杂查询还是得靠SQL
比如要统计每个月新增用户数、留存率、活跃度,这种带窗口函数、子查询、多条件分组的逻辑,用ORM拼出来代码又长又难懂。而原生SQL写起来直白清晰:
SELECT
DATE_TRUNC('month', created_at) AS month,
COUNT(*) AS new_users,
AVG(
CASE WHEN EXISTS (
SELECT 1 FROM user_actions
WHERE user_id = users.id
AND created_at >= users.created_at + INTERVAL '7 days'
) THEN 1 ELSE 0 END
) AS retention_rate
FROM users
GROUP BY month
ORDER BY month;
这段代码要是用ORM实现,估计得拆成好几块,维护起来头疼。
性能敏感场景绕不开SQL
做报表、数据导出、后台批量处理的时候,效率就是命。ORM为了安全和通用性,往往加了很多中间层,反倒成了拖累。我自己做过一个导出十万条订单的功能,ORM跑了两分钟,换成原生SQL配合流式读取,30秒搞定。
安全性也能自己把控
有人担心手写SQL容易有注入风险。其实只要用参数化查询,一样安全。比如Python里用psycopg2或pymysql,都支持占位符:
cursor.execute(
"SELECT * FROM orders WHERE user_id = %s AND status = %s",
(user_id, status)
)
比拼字符串安全多了,也比ORM的链式调用更直观。
什么时候可以不用ORM
小项目、工具脚本、数据清洗、后台管理这类不需要复杂模型映射的地方,直接写SQL省事又透明。尤其是你已经熟悉业务表结构的情况下,何必多绕一层?
当然,这不是否定ORM的价值。对于快速开发、团队协作、模型复用多的项目,ORM依然是利器。但别忘了它只是工具之一。就像厨房里不能只有电饭煲,炒菜还得用锅。
下次当你又要点开models.py准备写filter链的时候,不妨停下来想想:这事,一条SQL能不能搞定?