mysql大數據量之limit優化



背景:當數據庫里面的數據達到幾百萬條上千萬條的時候,如果要分頁的時候(不過一般分頁不會有這么多),如果業務要求這么做那我們需要如何解決呢?
我用的本地一個自己生產的一張表有五百多萬的表,來進行測試,表名為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連接查詢對應的分頁數據,可見並不是所有的連接查詢都會比
單查詢要慢,要依情況而定。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM