背景:當數據庫里面的數據達到幾百萬條上千萬條的時候,如果要分頁的時候(不過一般分頁不會有這么多),如果業務要求這么做那我們需要如何解決呢?
我用的本地一個自己生產的一張表有五百多萬的表,來進行測試,表名為big_data;
首先我們看如下幾條sql語句:
在這之前我們開啟profiling來監測sql語句執行的情況。
set profiling=1;
1.查詢從第10w條數據開始分頁10條
2.查詢從第20w條數據分頁10條
3.查詢從第30w條數據分頁10條
3.查詢從第300w條數據分頁10條
3.查詢從第500w條數據分頁10條
我們可以看出查詢從200w開始分頁的都還比較快,但從500w開始速度就變的很慢了,這個是不太讓人滿意的。
mysql> select id,my_name from big_data limit 5000000,10;
+---------+------------+
| id | my_name |
+---------+------------+
| 5000001 | kwCwziqhNu |
| 5000002 | NLpqMMwaJv |
| 5000003 | kskUTLXDbx |
| 5000004 | PtAvBtpubZ |
| 5000005 | whsuShiuvX |
| 5000006 | TcDLWzHNQT |
| 5000007 | qHmnEkjsmh |
| 5000008 | UQrmluqvgr |
| 5000009 | UzKeqpEbtQ |
| 5000010 | SkuvSePMpq |
+---------+------------+
10 rows in set (2.34 sec)
mysql> show profiles;
+----------+------------+--------------------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+--------------------------------------------------+
| 1 | 0.02591075 | select id,my_name from big_data limit 100000,10 |
| 2 | 0.05773150 | select id,my_name from big_data limit 200000,10 |
| 3 | 0.08253525 | select id,my_name from big_data limit 300000,10 |
| 4 | 1.38455375 | select id,my_name from big_data limit 3000000,10 |
| 5 | 2.34040775 | select id,my_name from big_data limit 5000000,10 |
+----------+------------+--------------------------------------------------+
5 rows in set, 1 warning (0.00 sec)
show profiles;
我們就如下兩種解決方法:
(1)、通過判斷id的范圍來分頁
select id,my_sn from big_data where id>5000000 limit 10;
也得到了分頁的數據,但是我們發現如果id不是順序的,也就是如果有數據刪除過的話,那么這樣分頁數據就會不正確,這個是有缺陷的。
(2)、通過連接查詢來分頁
我們可以先查詢500w條數據開始分頁的那10個id,然后通過連接查詢顯示數據
mysql> select b.id,b.my_name from big_data as b inner join (select id from big_data order by id limit 4500000,10) as tmp on tmp.id=b.id;
我們測試不同起始端的分頁數據
mysql> select b.id,b.my_name from big_data as b inner join (select id from big_data order by id limit 5000000,10) as tmp on tmp.id=b.id;
+---------+------------+
| id | my_name |
+---------+------------+
| 5000001 | kwCwziqhNu |
| 5000002 | NLpqMMwaJv |
| 5000003 | kskUTLXDbx |
| 5000004 | PtAvBtpubZ |
| 5000005 | whsuShiuvX |
| 5000006 | TcDLWzHNQT |
| 5000007 | qHmnEkjsmh |
| 5000008 | UQrmluqvgr |
| 5000009 | UzKeqpEbtQ |
| 5000010 | SkuvSePMpq |
+---------+------------+
10 rows in set (2.15 sec)
mysql> show profiles;
+----------+------------+------------------------------------------------------------------------------------------------------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+------------------------------------------------------------------------------------------------------------------------------------+
| 1 | 0.02591075 | select id,my_name from big_data limit 100000,10 |
| 2 | 0.05773150 | select id,my_name from big_data limit 200000,10 |
| 3 | 0.08253525 | select id,my_name from big_data limit 300000,10 |
| 4 | 1.38455375 | select id,my_name from big_data limit 3000000,10 |
| 5 | 2.34040775 | select id,my_name from big_data limit 5000000,10 |
| 6 | 0.00004200 | reset query cache |
| 7 | 0.01999275 | select b.id,b.my_name from big_data as b inner join (select id from big_data order by id limit 100000,10) as tmp on tmp.id=b.id |
| 8 | 0.03888825 | select b.id,b.my_name from big_data as b inner join (select id from big_data order by id limit 200000,10) as tmp on tmp.id=b.id |
| 9 | 0.37394450 | select b.id,b.my_name from big_data as b inner join (select id from big_data order by id limit 1000000,10) as tmp on tmp.id=b.id |
| 10 | 1.33475700 | select b.id,b.my_name from big_data as b inner join (select id from big_data order by id limit 3000000,10) as tmp on tmp.id=b.id |
| 11 | 2.14759000 | select b.id,b.my_name from big_data as b inner join (select id from big_data order by id limit 5000000,10) as tmp on tmp.id=b.id |
如果懷疑有緩存的緣故我們可以清楚緩存后來查詢
reset query cache;
show profile for query 3;//查看被記錄的第三條sql語句的執行情況
可以看出兩種方法查出來的數據都是一致的,但通過方法二的速度比之前單表查詢的速度快了一些。
分析:因為mysql分頁查詢是先把分頁之前數據都查詢出來了,然后截取后把不是分頁的數據給扔掉后得到的結果這樣,所以數據量太大了后分頁緩慢是可以理解的。
但是我們可以先把需要分頁的id查詢出來,因為id是主鍵id主鍵索引,查詢起來還是快很多的,然后根據id連接查詢對應的分頁數據,可見並不是所有的連接查詢都會比
單查詢要慢,要依情況而定。