剖析MySQL中優化distinct的技能。本站提示廣大學習愛好者:(剖析MySQL中優化distinct的技能)文章只能為提供參考,不一定能成為您想要的結果。以下是剖析MySQL中優化distinct的技能正文
有如許的一個需求: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) | +———————-+ | 806934 | +———————-+ 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 scan,但在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)
Sql中先選出分歧的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 | SIMPLE | 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 | SIMPLE | user_access | index | NULL | ind_user_access | 177 | NULL | 19546123 | Using index |