在看參考手冊的時候看到個案例
3.6.8 Calculating Visits Per Day
create table t1(year YEAR(4), month INT(2) UNSIGNED ZEROFILL, day INT(2) UNSIGNED ZEROFILL);
insert into t1 values(2000,1,1),(2000,1,20),(2000,1,30),(2000,2,2),(2000,2,23),(2000,2,23);
select * from t1;

QQ圖片20180726203424.png
首先要說明以下幾個函數(shù)
bit_count:
就是計算二進制里有多少個1
10的二進制是1010
bit_count(10) = 2
100的二進制是1100100
bit_count(123) = 3
bit_or:
按位或,就是如果兩邊一個位置上存在1,那這個位置就為1
拿上面10和100舉例
10 | 100 轉換為二進制就是 1010|1100100
1010
1100100
1101110
1<<day:
向左位移,向左位移幾位,然后用0填補
比如day=2
1<<2 = 100
day=4
1<<4 = 10000
回到主題,現(xiàn)在要計算出圖中每天的訪問量,可以看到day列中是存在重復記錄的,所以要去除,一般思路應該會寫出以下SQL:
mysql> select year,month,count(0) from (select year,month,count(day) from t1 group by year,month,day) as tmp group by year,month;
這個的確可以得到正確值,但是官方參考文檔里使用了更巧妙的算法
select year,month,bit_count(bit_or(1<<day)) from t1 group by year,month;
為了演示,現(xiàn)在將day設定為1,2,2,3好了,那就等于
bit_or(1<<1, 1<<2, 1<<2, 1<<3)
10 | 100 | 100 | 1000 => 110 | 100 | 1000 => 110 | 1000 => 1110
當110 | 100的時候,相同的值就不會發(fā)生變化,所以最后bit_count的結果就為3
插入2w條數(shù)據(jù)后,看下執(zhí)行計劃,第一種SQL執(zhí)行兩遍全表掃描
為了明確看到查詢性能,我們啟用profiling并關閉query cache:
SET profiling = 1;
SET query_cache_type = 0;
SET GLOBAL query_cache_size = 0;

image.png

image.png

image.png