MySQL的limit分頁性能測試加優化

平常咱們分頁時會用到MySQL的limit字段去處理,那麼使用limit時,有什麼須要優化的地方嗎?
咱們來作一個試驗來看看limit的效率問題:
環境:CentOS 6 & MySQL 5.7
一、建議一個實驗表:mysql

collect(id[主鍵], title[varchar], info[text], vtype[tinyint]);
Engine: MyISAM

二、關閉查詢緩存:
MySQL中的 query_cache_size 和 query_cache_type 參數。sql

mysql> show variables like 'query_cache%';                                                                 
+------------------------------+---------+
| Variable_name                | Value   |
+------------------------------+---------+
| query_cache_limit            | 1048576 |
| query_cache_min_res_unit     | 4096    |
| query_cache_size             | 1048576 |
| query_cache_type             | OFF     |
| query_cache_wlock_invalidate | OFF     |
+------------------------------+---------+
5 rows in set (0.06 sec)

查詢緩存命中狀況:Qcache_hits緩存

mysql> show status like '%qcache%';
+-------------------------+---------+
| Variable_name           | Value   |
+-------------------------+---------+
| Qcache_free_blocks      | 1       |
| Qcache_free_memory      | 1031832 |
| Qcache_hits             | 0       |
| Qcache_inserts          | 0       |
| Qcache_lowmem_prunes    | 0       |
| Qcache_not_cached       | 81      |
| Qcache_queries_in_cache | 0       |
| Qcache_total_blocks     | 1       |
+-------------------------+---------+
8 rows in set (0.00 sec)

關閉查詢緩存:測試

set global query_cache_size=0
set global query_cache_type=0

Note:優化

select SQL_NO_CACHE * from table_name;
使用SQL_NO_CACHE參數並不表明不使用緩存,而是這次查詢不會緩存,MySQL中若有緩存仍是會返回緩存數據,
也就是說,可能同一條sql,第一次查詢時間很長,第二次就很短。
我在實驗中,先是使用的xampp中的MariaDB,發現不管我怎麼設置(包括關閉緩存,清除緩存),都能使用到緩存,也就是我第二次查詢時間很短。 因此以後我使用了CentOS 6內網機中的MySQL
5.7作實驗。


三、開始試驗:spa

3.a、無索引狀況
collect表插入10萬條數據。【此時表無索引】code

mysql> select count(*) from collect;
+----------+
| count(*) |
+----------+
|   100001 |
+----------+
1 row in set (0.00 sec)

select id,title字段,limit 1000,1 很是快blog

mysql> FLUSH QUERY CACHE;
Query OK, 0 rows affected, 1 warning (0.03 sec)

mysql> select SQL_NO_CACHE id,title from collect limit 1000,10;
10 rows in set, 1 warning (0.07 sec)

select id,title字段,limit 90000,1 慢了索引

mysql> FLUSH QUERY CACHE;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select SQL_NO_CACHE id,title from collect limit 90000,10;
10 rows in set, 1 warning (2.02 sec)

select id字段,limit 90000,1 很是快it

mysql> FLUSH QUERY CACHE;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select SQL_NO_CACHE id from collect limit 90000,10;      
10 rows in set, 1 warning (0.02 sec)

那麼咱們想查詢title怎麼快呢?
網上有的解決方式爲:用id作條件去查 【可用,效率能夠】

mysql> FLUSH QUERY CACHE;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select SQL_NO_CACHE id,title from collect where id>=(select id from collect order by id limit 90000,1) limit 10;
10 rows in set (0.01 sec)

mysql> select SQL_NO_CACHE id,title from collect order by id limit 90000,10;
10 rows in set (2.07 sec)

以上能夠看出來,用id作limit,而後再以id爲條件查詢,效率比直接id,title作limit快的多。

3.b 加單個索引
那麼咱們以其餘字段作where條件呢?如vtype字段。
爲vtype創建索引:【該方法很慢】

ALTER TABLE collect ADD INDEX search(vtype);

用vtype作where條件作limit 90000,10

mysql> FLUSH QUERY CACHE;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select SQL_NO_CACHE id from collect where vtype=1 order by id limit 90000,10;
Empty set (2.50 sec)

vtype有索引爲什麼這麼慢呢?我的猜想多是作了全表掃描而沒走索引
試驗一下 limit 1000,10呢?

mysql> FLUSH QUERY CACHE;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select SQL_NO_CACHE id from collect where vtype=1 order by id limit 1000,10;
10 rows in set (0.03 sec)

計算一下 0.03*90 = 2.7 和 limit 90000,10 差很少

那麼加複合索引呢?會不會提升效率呢?

3.c、(vtype,id)複合索引 【只查主鍵很是快】

mysql> alter table collect add index search(vtype,id);
Query OK, 100001 rows affected (8.72 sec)
Records: 100001  Duplicates: 0  Warnings: 0

mysql> FLUSH QUERY CACHE;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select SQL_NO_CACHE id from collect where vtype=1 order by id limit 90000,10;
Empty set (0.01 sec)

mysql> FLUSH QUERY CACHE;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select SQL_NO_CACHE id,title from collect where vtype=1 order by id limit 90000,10;
Empty set (2.56 sec)

能夠看出來,(vtype,id)複合索引下,limit偏移量大的狀況下,只查詢主鍵id,是很是快的。


3.d、(id,vtype)複合索引 【沒有vtype,id快】

mysql> drop index search on collect;
Query OK, 100001 rows affected (4.31 sec)
Records: 100001  Duplicates: 0  Warnings: 0

mysql> select SQL_NO_CACHE id from collect where vtype=1 order by id limit 90000,10;      
Empty set (2.28 sec)

mysql> alter table collect add index search(id,vtype);    
Query OK, 100001 rows affected (6.46 sec)
Records: 100001  Duplicates: 0  Warnings: 0

mysql> select SQL_NO_CACHE id from collect where vtype=1 order by id limit 90000,10;
Empty set (0.07 sec)

mysql> select SQL_NO_CACHE id,title from collect where vtype=1 order by id limit 90000,10;
Empty set (1.99 sec)

(id,vtype)複合索引下,只查詢主鍵id的limit看起來好像和(vtype,id)複合索引沒什麼區別,可是我試驗中,將數據加到160萬,就能看出來,(vtype,id)複合索引幾乎不受影響,(id,vtype)複合索引卻開始變慢了。

那麼如今查詢到id了,咱們經過id去找title字段值。使用in去找,你會發現仍是很快的。

 

select SQL_NO_CACHE * from collect where id in(901744,901772,901773,901794);
4 rows in set (0.10 sec)

 

四、最後

再測試100萬,160萬,結論爲(vtype,id)複合索引查id,MySQL in()去查多個id的值,徹底能夠,查詢效率沒問題,仍是很快,不過再往上,我就沒再測試過了。

 

五、總結

以collect(id[主鍵], title[varchar], info[text], vtype[tinyint]); Engine: MyISAM表,爲例:

數據160萬,查詢條件vtype,查title字段

優化Limit步驟:

一、加(vtype,id)複合索引

二、select id from collect where vtype=1 limit 900000,10;

三、select id,title from collect where id in(1,2,3,4,5,6,7,8,9,10);

相關文章
相關標籤/搜索