本文整理自《高性能MySQL》第三版,修正了部分错误

计数器表

web应用中经常需要保存用户的朋友数,点击次数,文件下载次数等,如果在应用表里面保存计数器,那么在更新计数器时可能遇到并发文婷,因此创建要给独立的表存储计数器通常是个好主意,这样可以使计数器小且快,使用独立的表可以帮助避免查询缓存失效。

CREATE TABLE hit_counter (
    cnt int unsigned not null
) ENGINE=InnoDB;



网站的每次点击都会对计数器进行更新

UPDATE hit_counter set cnt = cnt + 1



问题在于,对于每一个想要更新这一行的事务来说,这条记录上都有一个全局互斥锁(mutex),这会使事务只能串行执行。要获得更高的并发更新性能,可以将计数器保存在多行中,每次随机选择一行更新。

CREATE TABLE hit_counter (
    slot tinyint unsigned not null,
    cnt int unsigned not null,
    PRIMARY KEY (slot)
) ENGINE=InnoDB;



然后预先在这张表里增加100行(根据业务需要确定)数据,更新时随机选择一行更新

UPDATE hit_counter set cnt = cnt + 1 where slot = ROUND(RAND() * 100);

注:mysql的RAND()函数返回0,1之间的随机浮点数



一个常见的需求是每隔一段时间开始一个新的计数器(例如,每天一个),可以通过修改表结构实现

CREATE TABLE daily_hit_counter (
    day date not null,
    slot tinyint unsigned not null,
    PRIMARY KEY (day,slot)
) ENGINE=InnoDB;



更新时只需要执行下面的语句

insert into daily_hit_counter values (CURRENT_DATE,ROUND(RAND()*100), 1)
ON DUPLICATE KEY UPDATE cnt = cnt + 1;



如果希望减少表的行数,可以写一个周期性的任务,合并所有结果到0号槽,并且删除所有其他的槽。实现起来也很简单,就不赘述了

12-20 05:06