有這樣的乙個需求:select count(distinct nick) from user_access_xx_xx;
這條sql用於統計使用者訪問的uv,由於單錶的資料量在10g以上,即使在user_access_xx_xx上加上nick的索引,
通過檢視執行計畫,也為全索引掃瞄,sql在執行的時候,會對整個伺服器帶來抖動;
root@db 09:00:12>select count(distinct nick) from user_access;
+———————-+
| count(distinct nick) |
+———————-+
程式設計客棧
| 8069 |
+———————-+
1 row in set (52.78 sec)
執行一次sql需要花費52.78s,已經非常的慢了
現在需要換一種思路來解決該問題:
我們知道索引的值是按照索引字段公升序的,比如我們對(nick,other_column)兩個欄位做了索引,那麼在索引中的則是按照nick,other_column的公升序排列:
我們現在的sql:select count(distinct nick) from user_access;則是直接從nick1開始一條條掃瞄下來,直到掃瞄到最後乙個nick_n,
那麼中間過程會掃瞄很多重複的nick,如果我們能夠跳過中間重複的nick,則效能會優化非常多(在oracle中,這種掃瞄技術為loose index ghswfqscan,但在5.1的版本中,mysql中還不能直接支援這種優化技術):
所以需要通過改寫sql來達到偽loose index scan:
root@db 09:41:30>select count(*) from ( select distinct(nick) from user_access)t ;
| count(*) |
+———-+
| 806934 |
1 row in set (5.81 sec)
s程式設計客棧ql中先選出不同的nick,最後在外面套一層,就可以得到nick的distinct值總和;
最重要的是在子查詢中:select distinct(nick) 實現了上圖中的偽loose index scan,優化器在這個時候的執行計畫為using index for group-by ,
需要注意的是mysql把distinct優化為group by,它首先利用索引來分組,然後掃瞄索引,對需要的nick只掃瞄一次;
兩個sql的執行計畫分別為:
優化寫法:
root@db 09:41:10>explain select distinct(nick) from user_access-> ;
+—-+————-+——————————+——-+—————+————-| id | select_type | table | type | possible_keys | key | key_len | ref | rows | extra |
+—-+————-+——————————+——-+—————+————-
| 1 | ****** | user_access | range | null | ind_user_access_nick | 67 | null | 2124695 | using index for group-by |
+—-+————-+——————————+——-+—————+————-
原始寫法:
root@db 09:42:55>explain select count(distinct nick) from user_access;
+—-+————-+——————————+——-+—————+————-
| id | select_type | table 程式設計客棧 | type | possible_keys | key | key_len | ref | rows | extra |
+—-+————-+——————————+——-+—————+————-
| 1 | ****** | user_access | index | null | ind_user_access | 177 | null | 19546123 | using index |
本文標題: 分析mysql中優化distinct的技巧
本文位址:
mysql優化案例分析
本文總結了一些工作常見的sql優化例子,雖然比較簡單,但很實用,希望對大家有所幫助。sql優化一般分為兩類,一類是sql本身的優化,如何走到合適的索引,如何減少排序,減少邏輯讀 另一類是sql本身沒有優化餘地,需要結合業務場景進行優化。即在滿足業務需求的情況下對sql進行改造,已提高sql執行速度,...
MySQL索引分析和優化
索引 索引用來快速地尋找那些具備特定值的記錄,任何mysql索引都以b 樹的形式儲存。假如沒有索引,執行查詢時mysql必須從第乙個記錄開始掃瞄整個表的任何記錄,直至找到符合需要的記錄。表裡面的記錄數量越多,這個操作的代價就越高。假如作為搜尋條件的列上已建立了索引,mysql無需掃瞄任何記錄即可迅速...
MySQL索引分析和優化
什麼是索引?索引用來快速地尋找那些具有特定值的記錄,所有mysql索引都以b 樹的形式儲存。如果沒有索引,執行查詢時mysql必須從第乙個記錄開始掃瞄整個表的所有記錄,直至找到符合要求的記錄。表裡面的記錄數量越多,這個操作的代價就越高。如果作為搜尋條件的列上已經建立了索引,mysql無需掃瞄任何記錄...