Db::name()比User::where()快5%–15%,差异源于对象实例化、属性映射、获取器/修改器触发及自动时间戳判断;但真实业务中该差距常被网络、IO等掩盖,仅高频中间件或导出脚本需优先考虑Db。

Db::name() 和 Model::where() 性能差异到底有多大
同等查询条件下,Db::name() 比 User::where() 快 5%–15%,主要差在对象实例化、属性映射、获取器/修改器触发、自动时间戳判断这几层开销。但这个差距只在单次简单查询中可测,在真实业务里基本被网络、IO、模板渲染掩盖。别为这点性能放弃模型——除非你在写高频中间件或导出脚本。
什么时候必须用 Db 而不能用 Model
以下场景模型几乎无法替代,硬套只会绕远路:
- 操作中间表(如
user_role),没建模型也无需业务逻辑,Db::name('user_role')->insert($data)最直接 - 跨库或动态表名(比如日志按月分表
log_202608),Model默认不支持运行时切换表名,而Db::name($table_name)可以 - 需要原生 SQL 表达式或复杂 UNION 查询,
Db支持query()和execute(),模型只能走raw()且限制多 - 批量插入大量原始数据(如导入 CSV),
Db::name()->insertAll()比循环User::create()少 90% 的对象构造开销
Model 不只是“封装了 Db”,它解决的是 Db 不管的事
Db 返回数组,Model 返回对象——这点差异会蔓延到整个调用链:
- 字段值自动类型转换:
$user->age是 int,Db::name()->find()里还是字符串 - 获取器(accessor)可用:
$user->getFullnameAttr()或直接$user->fullname拼接姓和名 - 软删除、自动时间戳、数据验证、事件回调(
onAfterUpdate)全靠模型层驱动 - 关联预载入:
User::with('posts.comments')->select()一行解决 N+1,Db 做不到 - 作用域(scope)复用:
User::scope('hot')->scope('published')->select(),Db 每次都得重写 where
Db 写法最容易踩的坑:5.1+ 版本的查询条件残留
这是线上事故高发点。下面写法在 ThinkPHP 5.1+ 中是危险的:
立即学习“PHP免费学习笔记(深入)”;
$user = Db::name('user');
$user->where('status', 1)->select(); // 第一次 OK
$user->where('score', '>', 90)->select(); // 实际执行:WHERE status = 1 AND score > 90 ❌
原因:5.1 开始 Db 查询对象不会自动清空 where 条件。正确姿势只有两种:
- 每次都用静态入口:
Db::name('user')->where(...)->select() - 若需复用对象,手动清理:
$user->removeOption('where')(注意它不清除order或field)
模型没这问题——每次 User::where() 都新建查询对象,天然隔离。



















