高效能Mysql(第3版)--網站點選計數器

QingChang發表於2020-12-06

如沒有特別說明,下面MYSQL通常是指《高效能Mysql(第3版)》這本書。
網站訪問量統計,自己實現思路:
每當使用者訪問頁面,前端初始化方法自動呼叫後端介面,進行訪問量統計,可以單獨建立一個計數器表,使用獨立的表可以幫助避免查詢快取失效。

udpate hit_counter set cnt=cnt+1 ;

但是當使用者在同一時刻網站訪問時,對於cnt欄位的修改可能會造成短時間阻塞。
(問題在於,對於任何想要更新這一行的事務來說,這條記錄上都有一個全域性的互斥鎖。這會使得這些事務只能序列執行。要活的更高的併發更新效能,也可以將計數器儲存在多行中,每次隨機選擇一行進行更新。)
在閱讀高效能Mysql第三版,提供了一種思路。
方法一:
如果不需要定時統計,可以建立表欄位。

create table hit_counter (slot tinyint unsigned not null, cnt int unsigned not null) ENGINE=INNODB

預先在這張表新增100行資料。現在選擇一個隨機的slot進行更新

update hit_counter set cnt=cnt+1 where slot =rand()*100

要獲得統計結果,需要使用下面的聚合查詢

select sum(cnt) from hit_counter;

當需要進行每日或者每月(每隔一段時間)開始一個新的計數器,要這麼設計表

create table daily_hit_counter(
day date not null,
slot tinyint unsigned not null,
cnt int unsigned not null,
primary key(day,slot)
) engine =innodb;

這裡不用預先生成行,用

on duplicate key update

代替

insert into  daily_hit_counter(day,slot,cnt) values(current_date,rand()*100,1) on duplicate key update cnt=cnt+1;

這裡day和slot構成聯合主鍵,統計當日的點選量。
如果希望減少表的行數,以避免表變得太大,可以寫一個週期執行的任務,合併所有結構到0號槽,並且刪除其他所有的槽。

UPDATE dayily_hit_counter AS c
INNER JOIN ( SELECT DAY, sum( cnt ) AS cnt , min( slot ) AS mslot FROM daily_hit_counter GROUP BY DAY ) AS x USING ( DAY ) 
SET c.cnt =
IF
    ( c.slot = x.mslot, x.cnt, 0 ),
    c.slot =
IF
    ( c.slot = x.mslot, 0, c.slot );
    delete from daily_hit_counter where slot <> 0 and cnt=0;

為什麼同樣是rand()結果不一樣。

本作品採用《CC 協議》,轉載必須註明作者和本文連結
love ,live in the moment.

相關文章