一個mysql最佳化的問題

來源:互聯網
上載者:User
**log表結構如下**id int(10) primary key #主鍵ip varchar(32) #iptime int(10) #時間channel varchar(128) #渠道id 普通索引status int(10) #狀態標識

channel欄位為幾個渠道號channel01,channel02...channel20
status為不同的狀態標識 比如1代表開啟次數,2代表關閉次數等

需求是:
統計不同渠道 不同狀態 每天的總ip數量
統計不同渠道 不同狀態 每天的去重ip數量
統計不同渠道 不同狀態 每天的新增ip數量(當天ip,且當天之前資料庫中不存在的ip)

下面為統計渠道channel01,狀態status=1的各項數量

目前的實現方法是:
比如2015-11-11當天的數量
先用php算出2015-11-11的淩晨時間戳記$begin和2015-11-12的淩晨時間戳記$end

**A-- 當天ip總數 $total**SELECT COUNT(*) FROM log WHERE time>={$begin} AND time<{$end} AND status=1 AND channel=channel01;**B-- 當天ip去重數 $group**SELECT COUNT(*) FROM log WHERE time>={$begin} AND time<{$end} AND status=1 AND channel=channel01 GROUP BY ip;**C-- 當天的ip   $ip_str (PHP處理)**SELECT ip FROM log WHERE time>={$begin} AND time<{$end} AND status=1 AND channel=channel01 GROUP BY ip;**D-- 當天ip在當天之前出現過的數量  $before**SELECT COUNT(*) FROM log WHERE ip IN ($ip_str) AND time<{$begin} GROUP BY ip;**E-- 新增的ip數量**$new = $group - $before

現在表中一共有52萬條資料,每天新增大概3萬條資料,去重後的也有2萬多,在執行第四步(語句D)的時候執行時間為3秒左右

請問有沒有什麼辦法可以最佳化這個sql語句,或者有沒有其它的什麼方法實現這個需求?

回複內容:

**log表結構如下**id int(10) primary key #主鍵ip varchar(32) #iptime int(10) #時間channel varchar(128) #渠道id 普通索引status int(10) #狀態標識

channel欄位為幾個渠道號channel01,channel02...channel20
status為不同的狀態標識 比如1代表開啟次數,2代表關閉次數等

需求是:
統計不同渠道 不同狀態 每天的總ip數量
統計不同渠道 不同狀態 每天的去重ip數量
統計不同渠道 不同狀態 每天的新增ip數量(當天ip,且當天之前資料庫中不存在的ip)

下面為統計渠道channel01,狀態status=1的各項數量

目前的實現方法是:
比如2015-11-11當天的數量
先用php算出2015-11-11的淩晨時間戳記$begin和2015-11-12的淩晨時間戳記$end

**A-- 當天ip總數 $total**SELECT COUNT(*) FROM log WHERE time>={$begin} AND time<{$end} AND status=1 AND channel=channel01;**B-- 當天ip去重數 $group**SELECT COUNT(*) FROM log WHERE time>={$begin} AND time<{$end} AND status=1 AND channel=channel01 GROUP BY ip;**C-- 當天的ip   $ip_str (PHP處理)**SELECT ip FROM log WHERE time>={$begin} AND time<{$end} AND status=1 AND channel=channel01 GROUP BY ip;**D-- 當天ip在當天之前出現過的數量  $before**SELECT COUNT(*) FROM log WHERE ip IN ($ip_str) AND time<{$begin} GROUP BY ip;**E-- 新增的ip數量**$new = $group - $before

現在表中一共有52萬條資料,每天新增大概3萬條資料,去重後的也有2萬多,在執行第四步(語句D)的時候執行時間為3秒左右

請問有沒有什麼辦法可以最佳化這個sql語句,或者有沒有其它的什麼方法實現這個需求?

你的這個表有很大問題。
IP不該用varchar(32),你想後續查詢時,這比較得多低效。通用的做法是用unsigned int配合inet_aton函數。
類似的channel欄位,如果固定不變,可以用enum代替varchar. 在varchar(128)上建索引,沒有比這更低效的了。實在不想用enum可以考慮對局部做索引,比如前12個字元,具體看情況。
time欄位應該納入索引。你建一個索引,包含三個欄位(channel, status, time),順序很重要,少的在前多的在後。

d中in的效率比較低,用所有ip減1天前所有ip,group by 預設顯示最上面的一條資料,時間上可能還要排序吧

去重IP的SQL可以使用如下改進:
B) 當天ip去重數

SELECT COUNT(DISTINCT ip)   FROM log  WHERE time >= {$begin}        AND time < {$end}        AND status = 1        AND channel = channel01;

C) 當天ip去重列表

SELECT DISTINCT ip  FROM log  WHERE time >= {$begin}        AND time < {$end}        AND status = 1        AND channel = channel01;

D) 當天ip在當天之前出現過的去重數量 寫法類似於B

這種問題應該用計數器來解決,盡量避免複雜邏輯查詢,不然資料量足夠多的時候很難搞的。
計數器可以直接用db或者memcache,redis之類來做。
或者每天定時跑指令碼進行資料統計,即時查看mysql不合適

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.