You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQLite中UPSERT(ON CONFLICT)与UPDATE/INSERT双查询的性能对比

回答

性能差异

原生UPSERT确实比双查询方案更快,但差距大小要看具体场景:

  • 单条操作:差异微乎其微。原生UPSERT是单次SQL请求、单轮索引查找;双查询是两次请求,但因为name有唯一索引,UPDATE的查找速度极快,实际使用中几乎感知不到区别。
  • 批量操作:当大量执行upsert时,原生UPSERT的优势会凸显——它不需要在PHP层做分支判断,减少了PHP与SQLite的交互次数;同时SQLite内部处理冲突的逻辑更高效,避免了两次重复的索引查找,批量场景下性能能提升20%-50%(具体取决于数据量)。

是否值得做版本适配?

分两种情况:

  • 如果你的业务有高频批量upsert需求(比如每秒数百次以上),或者对性能有极致要求,那绝对值得做版本判断。只需要几行代码就能获取SQLite版本并分支执行:
$sqliteVersion = SQLite3::version()['versionNumber'];
// 3024000对应SQLite 3.24.0版本
$useNativeUpsert = $sqliteVersion >= 3024000;
  • 如果只是低频单条upsert,双查询方案的性能完全够用,没必要增加代码复杂度,维护成本反而更高。

双查询方案在新版本的表现

在新版本SQLite中,双查询方案的性能依然能满足绝大多数日常需求:

  • 事务包裹下,两次操作的磁盘IO会被合并(SQLite事务会延迟写操作到提交时执行),不会额外增加磁盘开销。
  • 唯一索引的存在让UPDATE的查找效率拉满,几乎没有额外损耗。
  • 除非你有每秒数千次以上的upsert请求,否则双查询的性能瓶颈不会显现。

额外提醒

  • 无论用哪种方案,一定要包裹在事务中!如果没有事务,双查询方案会触发两次磁盘刷新,性能直接暴跌;原生UPSERT虽然是单条语句,但无事务的话每次操作都会刷盘,同样影响性能。
  • 双查询方案要注意并发场景:高并发下可能出现UPDATE后、INSERT前,其他进程插入了同一条数据,导致唯一索引冲突。这种情况可以在INSERT时捕获异常,重试一次UPDATE即可——而原生UPSERT本身内置了冲突处理,不会出现这个问题。

内容的提问来源于stack exchange,提问作者O. Jones

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 07:01:16