1. 程式人生 > >第十九篇:Mysql兩次Group by和ip轉數字作比較的一次優化

第十九篇:Mysql兩次Group by和ip轉數字作比較的一次優化

業務場景:兩張表,ipconfig_group表存了單位和 ip 起始段資訊

圖片

visit_info表儲存了訪問次數,失敗次數,訪問流量,使用者ip等資訊

圖片

兩張表的關係為:
    一個部門下有若干ip段,對應的下面表的visitorip,每個visitorip有訪問次數,失敗次數,流量
    現在,要按部門統計各部門的訪問次數,失敗次數,流量
通常的做法:
第一步:統計visit_info 表各個ip的次數

第二步:統計這些ip對應哪個部門,相同部門的對應欄位疊加 

常規方法:如果先搞定第一步,然後程式處理第二步,那麼就需要用java模擬資料庫查詢的Group by
方法如下: 
圖片

 
這裡是只統計了流量,因為是已經做好的一個需求的邏輯,用java程式處理比較好理解
現在要統計3個欄位累加,那麼就只能定義一個Map<String,List<Integer>>,先遍歷第一步返回的結果list
String是部門作為鍵,List<Integer>是後3個欄位,放在一個List<Map<String,List<Integer>>>中
也可以用Map<String,Integer>存,放在List<Map<String,Map<String,Integer>>>,然後遍歷最外層的list

像上圖加紅字標註的地方,那是一個簡單的Integer相加,這裡因為有3個要累加,
所以要寫一個實現相同鍵(部門)對應的值(List<Integer>或Map<String,Integer>)累加的方法,怎麼疊加很簡單就不說了

可以想見,寫起來非常麻煩,這就是java代替資料庫Group by的方法邏輯吧

優化如下:首先肯定需要組合查詢,第一步還是查一張表統計ip:
結果如下
圖片


第二步:組合查詢,查詢ip在符合的ip段內的部門統計結果
這裡先要用到一個函式:inet_aton(ip),這個函式可以將任意一個標準的ip值:XXX.XXX.XXX.XXX轉換成整數int型(最多10位)
圖片
好了所有的路鋪平了,只差複合sql查出來就行了:
圖片

所有的邏輯,在資料庫層面做完,程式再也不用那麼麻煩,程式碼簡化一大截
看,現在就一句程式碼了^^^^^^^^
圖片
效能的問題,暫時沒考慮,因為截圖測試的資料量很少,
但是如果是程式自己實現Group by,只是分步驟,資料庫查詢sql簡單了,但是次數就非常多了,總的時間並不見得會短

這裡有幾個關鍵:
1、Group by用java程式實現,雖然是笨了點,但是也為以後做統計給了一種思路
2、ip段作比較用了mysql的inet_aton函式,事實上一開始我沒想到有這個函式,實在是程式實現統計的邏輯太煩想圖簡單才去查閱
這也給了我們一個思路,上面截圖最大的ip也才是10位的整型。mysql還有一個inet_ntoa函式用來將數字轉為IP值

資料庫優化原則:欄位型別定義使用最合適(最小),最簡單的資料型別
那麼我們存進去的時候就可以考慮存為整型,取出來的時候用inet_ntoa
()轉為ip
附:a.b.c.d 的ip number是:
a * 2的11次方 + b * 2的10次方 + c * 2的8次方 + d * 2的0次方