這時MySQL用到了clicks索引進行查詢,但是結果集比userid還要大!看來還要再進行限制:
MySQL> desc select * from imgs use index (clicks) where userid='admin' and clicks>1000 order by clicks desc limit 10加到1000的時候結果集變成了312條,排序效率應該是可以接受。
不過,采用換索引這種優化方式需要取一個采樣點,比如這個例子中的1000這個數字,這樣,對userid的每個數值,都要去找一個采樣點,這樣對程序來說是很難辦的。如果按1000取樣的話,那麼userid='7mini'這個例子中,取到的結果將不會是8條,而是2條,給用戶造成了困惑。
當然還有另一種辦法,加入雙索引:
create index userid_clicks on imgs (userid, clicks)
MySQL> desc select * from imgs where userid="admin" order by clicks desc limit 10;
+----+-------------+-------+------+----------------------+---------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | extra |
+----+-------------+-------+------+----------------------+---------------+---------+-------+------+-------------+
| 1 | simple | imgs | ref | userid,userid_clicks | userid_clicks | 51 | const | 2944 | using where |
+----+-------------+-------+------+----------------------+---------------+---------+-------+------+-------------+
1 row in set (0.00 sec)
這時可以看到,結果集還是2944條,但是extra中的filesort不見了。這時MySQL使用userid_clicks這個索引去查詢,這不但能快速查詢到userid="admin"的所有記錄,並且結果是根據clicks排好序的!所以不用再把這個結果集讀入內存一條一條排序了,效率上會高很多。
但是用多字段索引這種方式有個問題,如果查詢的sql種類很多的話,就得好好規劃一下了,否則索引會建得非常多,不但會影響到數據insert和update的效率,而且數據表也容易損壞。
以上是對索引優化的辦法,因為原因可能會比較復雜,所以寫得比較的長,一般好好優化了索引之後,MySQL的效率會提升n個檔次,從而也不需要考慮增加機器來解決問題了。
但是,MySQL甚至所有數據庫,可能都不好解決limit的問題。在mysql中,limit 0,10只要索引合適,是沒有問題的,但是limit 100000,10就會很慢了,因為MySQL會掃描排好序的結果,然後找到100000這個點,取出10條返回。要找到100000這個點,就要掃描100000條記錄,這個循環是比較耗時的。不知道會不會有什麼好的算法可以優化這個掃描引擎,我冥思苦想也想不出有什麼好辦法。對於limit,目前直至比較久遠的將來,我想只能通過業務、程序和數據表的規劃來優化,我想到的這些優化辦法也都還沒有一個是萬全之策,往後再討論。