1. 程式人生 > >order by 不走索引的思考

order by 不走索引的思考

今天早上檢視網站,發現非常慢!進linux 用top檢視,發現mysql cpu到了100%。開始懷疑是mysql效能的問題,不會10萬條資料就卡成這樣吧?雖然我的linux是在伺服器上放了個虛擬機器,但也不至於10萬條記錄掛啊? 網上找了一大把文章,my.cnf也設定了,我虛擬機器記憶體是2G,將key_buf設定成512M 還是卡。非常鬱悶!

最後沒辦法,只能用explain來找原因了。結果還真找到了。所以說用mysql寫查詢語句,一定要注意索引,一個不小心,效能那是十萬八千里。OK,下面分享下查詢過程:

首先上原始的查詢語句,我只用了一個id欄位,方便檢查。

explain select id from collect where vtype=1 order by id asc;
+----+-------------+---------+------+---------------+-------+---------+-------+-------+-----------------------------+
| id | select_type | table   | type | possible_keys | key   | key_len | ref   | rows | Extra                       |
+----+-------------+---------+------+---------------+-------+---------+-------+-------+-----------------------------+
| 1 | SIMPLE      | collect | ref | vtype         | vtype | 5       | const | 93237 | Using where; Using filesort |
+----+-------------+---------+------+---------------+-------+---------+-------+-------+-----------------------------+
看上面,最後的Extra 部分:竟然出現 Using filesort ! 我暈,全表查詢。但是 prossible keys 已經使用到了vtype啊? 看來並不是where 條件的問題。

為了測試,將2條語句分別執行下看:

mysql> select id from collect where vtype=1 order by id asc limit 0,20;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
| 11 |
| 12 |
| 13 |
| 14 |
| 15 |
| 16 |
| 17 |
| 18 |
| 19 |
| 20 |
+----+
20 rows in set (10.28 sec)
查詢20條資料,花了 10.28 秒! 非常的暈。

再看:

mysql> select id from collect where vtype=1 limit 0,20;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
| 11 |
| 12 |
| 13 |
| 14 |
| 15 |
| 16 |
| 17 |
| 18 |
| 19 |
| 20 |
+----+
20 rows in set (0.01 sec)
少了order by 基本上秒查!

為什麼會出現以上問題呢?order by id asc, id 欄位可是主鍵啊,按理說應該是非常快的索引,但是mysql 好像並沒有用到。再測試

mysql> explain select * from collect order by id asc;
+----+-------------+---------+------+---------------+------+---------+------+--------+----------------+
| id | select_type | table   | type | possible_keys | key | key_len | ref | rows   | Extra          |
+----+-------------+---------+------+---------------+------+---------+------+--------+----------------+
| 1 | SIMPLE      | collect | ALL | NULL          | NULL | NULL    | NULL | 103997 | Using filesort |
+----+-------------+---------+------+---------------+------+---------+------+--------+----------------+
看上面的分析,我直接select * order by id asc ,也是用到了filesort ,用到了這個肯定查詢在10秒以上了。

mysql> explain select id from collect order by id asc;
+----+-------------+---------+-------+---------------+---------+---------+------+--------+-------------+
| id | select_type | table   | type | possible_keys | key     | key_len | ref | rows   | Extra       |
+----+-------------+---------+-------+---------------+---------+---------+------+--------+-------------+
| 1 | SIMPLE      | collect | index | NULL          | PRIMARY | 4       | NULL | 103997 | Using index |
+----+-------------+---------+-------+---------------+---------+---------+------+--------+-------------+
而上面的,將* 改成id ,Using index 了,看來直接查詢id 會使效能提高。

mysql> explain select id,url,title from collect order by id asc;
+----+-------------+---------+------+---------------+------+---------+------+--------+----------------+
| id | select_type | table   | type | possible_keys | key | key_len | ref | rows   | Extra          |
+----+-------------+---------+------+---------------+------+---------+------+--------+----------------+
| 1 | SIMPLE      | collect | ALL | NULL          | NULL | NULL    | NULL | 103997 | Using filesort |
+----+-------------+---------+------+---------------+------+---------+------+--------+----------------+
1 row in set (0.00 sec)
而再加上另外的欄位,order by 就沒任何效能提高了。還是Using fielsort !

從上面可以看出order by 不能亂用!不知道網上哪個傻逼說用了limit 最好用order by 這樣會讓分頁的效能加快!簡直是放屁。經過實際測試,limit 和order by 沒有任何關聯!而以前寫程式的時候經常會用order by id asc 。 可能是資料從來沒有上過10萬條的緣故,感覺還行,今天用了10萬條採集資料做測試,慢得一塌糊塗!

好了,現在仔細想想order by 用到索引的場合:

1) 如果select 只查詢索引欄位,order by 索引欄位會用到索引,要不然就是全表排列;

2) 如果有where 條件,比如where vtype=1 order by vtype asc . 這樣order by 也會用到索引!

3) 綜上,如果order by 真的影響limit的話,那麼就請在沒有where 查詢的時候order by id(主鍵), 有where 查詢的時候,order by (索引) 欄位。

4) 別迷信網上文章,多explain,並且要相信mysql 依然很堅挺,別出現慢的情況就想,免費的效能就這樣?

測試繼續,到了100條記錄,1000萬條再來測試mysql 的效能。

測試環境:目前資料量1.4G,10萬記錄,core 4200,4G記憶體,vm6.0虛擬機器(Linux centos5 , 2G記憶體,60G硬碟)下測試!