不用ORM直接写SQL行吗?别被框架惯坏了

很多人学编程时,一上来就被塞了各种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能不能搞定?