它的本质是一条看似简单的“自增”语句在底层被转化为UPDATE posts SET likes likes ? WHERE id ?。虽然它在 SQL 层面是原子的不会读到脏数据但在高并发场景下它会导致严重的行锁等待 (Row Lock Wait)和索引页争用 (Index Page Contention)。对于热门帖子这行代码就是导致数据库 CPU 飙升、响应延迟激增的元凶**。如果把数据库比作银行柜台increment()是排队改账本。流程顾客 A 走到柜台 - 柜员锁定账本第 10 页加行锁- 读取当前余额 100 - 计算 1001101 - 写入 101 - 解锁。并发问题顾客 B、C、D… 同时来改第 10 页。他们必须串行排队。A 没办完B 只能干等Lock Wait。后果队伍越来越长柜台处理速度越来越慢最后大堂经理连接池崩溃。RedisINCR是电子计数器。流程顾客按一下按钮数字自动1。无需排队微秒级完成。优势完全异步无锁竞争。核心逻辑别让所有人都去抢同一本账本。把记账工作交给高速缓存账本只在最后对一次总账。一、SQL 本质它到底做了什么1. 生成的 SQLLaravel 的increment方法最终生成UPDATEpostsSETlikeslikes1WHEREid123;-- 如果 $count 1UPDATEpostsSETlikeslikes5WHEREid123;2. 原子性保证 (Atomicity)正确性在 InnoDB 引擎中这条语句是原子的。它不是SELECT likes-PHP计算-UPDATE。它是直接在存储引擎层完成读取计算写入。结论数据不会错不会少加这是它唯一的优点。3. 锁机制 (Locking)行锁 (Row Lock)InnoDB 会对id123这一行加X锁 (Exclusive Lock)。持续时间直到事务提交。影响其他任何试图修改或锁定该行的事务包括另一个increment都必须等待。 核心洞察increment保证了数据的“正确性”但牺牲了系统的“并发性”。在低并发下没问题在高并发下是灾难。二、并发危害为什么它是热点杀手1. 行锁等待 (Lock Wait)场景爆款文章每秒 1000 人点赞。现象Thread 1 获得锁执行 UPDATE (耗时 1ms)。Thread 2-1000 进入Lock Wait Queue。Thread 2 等待 1msThread 1000 等待 1000ms (1秒)。后果接口响应时间线性增长用户感觉“卡死”。2. 上下文切换开销 (Context Switch Overhead)机制MySQL 线程不断在“运行”和“等待锁”之间切换。后果CPU 大量时间花在调度线程上而非执行 SQL 上。sys态 CPU 使用率飙升。3. 索引页争用 (Index Page Latch Contention)机制id是主键聚簇索引。频繁更新同一行会导致该索引页在 Buffer Pool 中被频繁读写。后果即使没有行锁等待内存层面的Latch (闩锁)竞争也会限制吞吐量。4. Binlog 压力机制每次UPDATE都会生成 Binlog 日志。后果高频小事务导致 Binlog 文件迅速膨胀主从同步延迟增加。三、性能优化如果必须用 DB怎么救如果你不能引入 Redis必须在 MySQL 层面优化1. 批量合并 (Batching)策略不要在每个请求中都调用increment。实现在 PHP 内存中累计计数。每隔 1 秒或每满 100 次执行一次DB::...-increment(likes, 100)。效果将 100 次行锁竞争合并为 1 次。风险服务重启会丢失未刷新的计数。2. 减少事务范围策略确保increment在一个极短的事务中执行尽快提交。代码DB::transaction(function()use($postId){DB::table(posts)-where(id,$postId)-increment(likes);// 不要在这里做其他耗时操作});3. 乐观锁重试 (Optimistic Locking Retry) -不推荐用于计数说明乐观锁适合状态变更不适合高频计数因为冲突率太高重试会导致更严重的 CPU 浪费。四、替代方案架构级解法方案 ARedis INCR 异步落库 (最佳实践)流程写Redis::incr(post:{$id}:likes)。原子操作无锁微秒级。读直接读 Redis 获取点赞数。同步定时任务每分钟将 Redis 计数同步到 MySQL。消息队列每次INCR发送 MQ消费者批量更新 MySQL。优势彻底解除数据库行锁瓶颈支撑万级 QPS。一致性最终一致性。用户看到的可能比实际多/少几秒但可接受。方案 BMySQL 延迟更新 (Write-Behind)流程PHP 接收请求将(post_id, user_id)放入本地内存数组或 APCu。当数组达到阈值如 50 个一次性执行UPDATE ... SET likes likes 50。优势减少 DB 交互次数。劣势单机部署有效集群部署复杂。方案 C分表/分库 (Sharding)流程将点赞记录分散到多个表中。劣势架构复杂度极高对于单纯的计数场景杀鸡用牛刀。 总结原子化“DB Increment”全景图维度关键点本质基于行锁的原子更新高并发下的性能瓶颈SQL 行为UPDATE table SET col col 1 WHERE id ?主要危害行锁等待、上下文切换、Binlog 膨胀适用场景低频更新、非热点数据、强一致性要求极高禁忌场景爆款文章点赞、秒杀库存扣减、高频计数器最佳替代Redis INCR 异步持久化PHP 隐喻Mutex Lock on Database Row公式Throughput 1 / (Lock_Wait_Time Execution_Time)终极心法DB Increment 的本质是“用串行化换取正确性”。在低并发时它是安全的捷径在高并发时它是致命的堵塞点。别让数据库承担它不该承担的计数压力。于原子中见安全于锁中见瓶颈以架构为尺解单点之牛于高并发工程中求吞吐之真。行动指令审查代码找出项目中所有的increment调用。评估频率哪些是热点数据如文章点赞、视频播放量重构热点将热点计数迁移到 RedisINCR。保留冷点低频数据如文章评论数、后台统计可以保留 DBincrement简化架构。思维升级记住数据库擅长存数据和复杂查询但不擅长高频简单计数。把计数交给 Redis把存储交给 MySQL。