mysql分頁查詢關鍵_MySQL優化教程之超大分頁查詢

背景

基本上只要是做后臺開發,都會接觸到分頁這個需求或者功能吧。基本上大家都是會用MySQL的LIMIT來處理,而且我現在負責的項目也是這樣寫的。但是一旦數據量起來了,其實LIMIT的效率會極其的低,這一篇文章就來講一下LIMIT子句優化的。

LIMIT優化

很多業務場景都需要用到分頁這個功能,基本上都是用LIMIT來實現。

建表并且插入200萬條數據:

# 新建一張t5表

CREATE TABLE `t5` (

`id` int NOT NULL AUTO_INCREMENT,

`name` varchar(50) NOT NULL,

`text` varchar(100) NOT NULL,

PRIMARY KEY (`id`),

KEY `ix_name` (`name`),

KEY `ix_test` (`text`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

# 創建存儲過程插入200萬數據

CREATE PROCEDURE t5_insert_200w()

BEGIN

DECLARE i INT;

SET i=1000000;

WHILE i<=3000000 DO

INSERT INTO t5(`name`,text) VALUES('god-jiang666',concat('text', i));

SET i=i+1;

END WHILE;

END;

# 調用存儲過程插入200萬數據

call t5_insert_200w();

在翻頁比較少的情況下,LIMIT是不會出現任何性能上的問題的。

但是如果用戶需要查到最后面的頁數呢?

通常情況下,我們要保證所有的頁面可以正常跳轉,因為不會使用order by xxx desc這樣的倒序SQL來查詢后面的頁數,而是采用正序順序來做分頁查詢:

select * from t5 order by text limit 100000, 10;

73b22209562edda340c085544ce8f0fe.png

采用這種SQL查詢分頁的話,從200萬數據中取出這10行數據的代價是非常大的,需要先排序查出前1000010條記錄,然后拋棄前面1000000條。我的macbook pro跑出來花了5.578秒。

接下來我們來看一下,上面這條SQL語句的執行計劃:

explain select * from t5 order by text limit 1000000, 10;

a57b88672a6b44d8a963322c45544b5d.png

從執行計劃可以看出,在大分頁的情況下,MySQL沒有走索引掃描,即使text字段我已經加上了索引。

這是為什么呢?

回到MySQL索引(二)如何設計索引中有提及到,MySQL數據庫的查詢優化器是采用了基于代價的,而查詢代價的估算是基于CPU代價和IO代價。

如果MySQL在查詢代價估算中,認為全表掃描方式比走索引掃描的方式效率更高的話,就會放棄索引,直接全表掃描。

這就是為什么在大分頁的SQL查詢中,明明給該字段加了索引,但是MySQL卻走了全表掃描的原因。

然后我們繼續用上面的查詢SQL來驗證我的猜想:

explain select * from t5 order by text limit 7774, 10;

6fa7f5496952ea16b608fe8d16cf8b26.png

explain select * from t5 order by text limit 7775, 10;

6f2fa8b1f516a15e24b2d68aacd9d607.png

以上的實驗均在我的mbp上運行的,在7774這個臨界點上,MySQL分別采用了索引掃描和全表掃描的查詢優化方式。

所以可以認為MySQL會根據它自己的代價查詢優化器來判斷是否使用索引。

由于MySQL的查詢優化器的算法核心是我們無法人工干預的,所以我們的優化思路就要著手于如何讓分頁維持在最佳的的分頁臨界點。

優化方式

1、使用覆蓋索引

如果一條SQL語句,通過索引可以直接獲取查詢的結果,不再需要回表查詢,就稱這個索引為覆蓋索引。

在MySQL數據庫中使用explain關鍵字查看執行計劃,如果extra這一列顯示Using index,就表示這條SQL語句使用了覆蓋索引。

讓我們來對比一下使用了覆蓋索引,性能會提升多少吧。

# 沒有使用覆蓋索引

select * from t5 order by text limit 1000000, 10;

963ba371e7c45ea77925d71c2be26e0c.png

2c3aa6528e9954dc5bcc8bb3dfbc2ef6.png

這次查詢花了3.690秒,讓我們看一下使用了覆蓋索引優化會提升多少性能吧。

# 使用了覆蓋索引

select id, `text` from t5 order by text limit 1000000, 10;

9e3b1b637feb7e155261cc2b4bc6781b.png

f72c7ea9be1fe26df7735f6b773786d4.png

從上面的對比中,超大分頁查詢中,使用了覆蓋索引之后,花了0.201秒,而沒有使用覆蓋索引花了3.690秒,提高了18倍多,這在實際開發中,就是一個大的性能優化了。(該數據在我的mbp上運行得出)

2、子查詢優化

因為實際開發中,用SELECT查詢一兩列操作是非常少的,因此上述的覆蓋索引的適用范圍就比較有限。

所以我們可以通過把分頁的SQL語句改寫成子查詢的方法獲得性能上的提升。

select * from t5 where id>=(select id from t5 order by text limit 1000000, 1) limit 10;

36e12ab40b61e08ce9a00862186f5a83.png

其實使用這種方法,提升的效率和上面使用了覆蓋索引基本一致。

但是這種優化方法也有局限性:

這種寫法,要求主鍵ID必須是連續的

Where子句不允許再添加其他條件

3、延遲關聯

和上述的子查詢做法類似,我們可以使用JOIN,先在索引列上完成分頁操作,然后再回表獲取所需要的列。

select a.* from t5 a inner join (select id from t5 order by text limit 1000000, 10) b on a.id=b.id;

e210992b1f3eb780947eccde90bff68f.png

從實驗中可以得出,在采用JOIN改寫后,上面的兩個局限性都已經解除了,而且SQL的執行效率也沒有損失。

4、記錄上次查詢結束的位置

和上面使用的方法都不同,記錄上次結束位置優化思路是使用某種變量記錄上一次數據的位置,下次分頁時直接從這個變量的位置開始掃描,從而避免MySQL掃描大量的數據再拋棄的操作。

select * from t5 where id>=1000000 limit 10;

f0dd6a10ad580ee43021462e3e4febf8.png

根據以上實驗,不難得出,由于使用了主鍵索引做分頁操作,SQL的性能是最快的。

總結

介紹了超大分頁查詢性能過差的原因,還有分享了幾個優化思路

超大分頁的優化思路就是讓分頁的SQL盡量在最佳的性能區間執行,不要觸發全表掃描即可

希望以上的分享,可以讓你們在MySQL這條路上少走彎路~~~

參考資料

《MySQL性能優化》第六章 查詢優化性能

《數據庫查詢優化器的藝術》

到此這篇關于MySQL優化教程之超大分頁查詢的文章就介紹到這了,更多相關MySQL超大分頁查詢內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/529554.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/529554.shtml
英文地址,請注明出處:http://en.pswp.cn/news/529554.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

mysql r_R之RMySQL

linux&#xff0c;mysql和R的版本信息&#xff1a;Linux naci 3.19.0-16-generic #16-Ubuntu SMPServer version: 5.6.24-0ubuntu2 (Ubuntu)R version 3.1.2 (2014-10-31) -- "Pumpkin Helmet"mysql的linux安裝&#xff0c;參照上一篇關于liunx下安裝mysql的文章。1.…

mysql 字符轉換函數是_MySQL日期和字符串轉換函數

Mysql中to_char()和str_to_date()函數轉載路徑&#xff1a;https://blog.csdn.net/ricardo_mli/article/details/802175121.字符串轉換成日期格式str_to_date(date,’%Y-%m-%d’)----->相當于Oracle中的to_char();例子&#xff1a;INSERT INTOt_order(order_time)VALUES(str…

mysql數據加百分號_使用MySQL SELECT語句時,在每個值的末尾添加一個百分號(%)...

要在末尾添加百分號&#xff0c;請使用CONCAT()函數。讓我們首先創建一個表-mysql> create table DemoTable(StudentId int NOT NULL AUTO_INCREMENT PRIMARY KEY,StudentName varchar(100),StudentScore int);使用插入命令在表中插入一些記錄-mysql> insert into DemoTa…

mysql 分頁 jdbc_JDBC調用MySQL分頁存儲過程實現(一)

DROP PROCEDURE IF EXISTS pro_pager;CREATE DEFINER root% PROCEDURE pro_pager(in p_pageNo int, /*當前頁*/in p_perPageCnt int, /*每頁記錄數*/in p_sql VARCHAR(2000), /*查詢sql語句*/out v_totalRowsCnt int, /*記錄總條數*/out v_totalPageCnt int) /*記錄總頁數*/BE…

mariadb mysql表_mysql/mariadb學習記錄——創建刪除數據庫、表的基本命令

查看已有的數據庫&#xff1a;mysql>show databases;--------------------| Database |--------------------| information_schema || test |--------------------2 rows in set (0.05 sec)新建數據庫語句:mysql>create database wzu;Query OK,1 row affected (0.05sec)m…

zabbix proxy mysql_zabbix proxy 配置

在監控大量服務器時&#xff0c;如果將所有的請求都發送到一個zabbix server上&#xff0c;將會對我們的zabbix server造成很大的壓力&#xff0c;我們在規劃多個區域或機房進行監控的時候&#xff0c;會考慮到使用zabbix proxy 來代理zabbix server 的部分功能。zabbix server…

mysql修改數據庫結構用哪一項_mysql alter修改數據庫表結構用法

1.alter操作表字段(1)增加字段alter table 表名 add 字段名 字段類型&#xff1b;alter table student add name varchar(10)&#xff1b;(2)修改字段alter table 表名 change 舊字段名 新字段名 字段類型&#xff1b;alter table 表名 modify 字段名 字段類型&#xff1b;//修…

mvc mysql linq_MVC3+Linq to sql 顯示數據庫中數據表的數據

1&#xff1a;首先創建asp.net mvc3應用程序 2&#xff1a;創建項目完成后 找到controllers文件鼠標右擊選擇添加控制器 3 為models文件夾添加一個linq to sql類文件&#xff0c;然后把數據庫中的數據庫復制進來。如截圖操作 4&#xff1a;添加控制器好后會生成一個HomeControl…

bash給腳本加進度條_shell腳本實現多彩進度條

代碼如下&#xff1a;1 #!/bin/bash2 i0;3 str""4 arr("|" "/" "-" "\\")5 while [ $i -le 100 ]6 do7 let indexi%48 let indexcolori%89 let color30indexcolor10 printf "\e[0;$color;1m[%-100s][%d%%]%c\r" &…

koa mysql mongodb_koa 操作MongoDB數據庫

安裝安裝MongoDBnpm install mongodb --save引入中間件引入mongodb下面的連接模塊MongoClient// 引入MongoDB 連接模塊const MongoClient MongoDB.MongoClient;配置中間件定義數據庫連接的地址以及配置數據庫的名稱let url "mongodb://localhost:27017/";let dbNam…

mysql 64位 安裝1045_MySql?安裝時的1045錯誤

MySql 安裝到最后一步遇到1045錯誤Access denied for user rootlocalhost (usingpassword:YES)解決方案一&#xff1a;卸載MySQL&#xff0c;重新安裝1, 卸載MySQL2, 刪除目錄 C:\Documents and Settings\All Users\ApplicationData\MySQL,還要刪除MySQL安裝目錄3, 重新安裝MyS…

mysql工作表格制作教程_Access制作復雜報表

何制作復雜報表利用excel輸出復雜報表 在讀這篇文章以前首先要提醒大家&#xff0c;Access 本身的報表也具有很強的實用性和強大的功能&#xff0c;只有當你發掘了其本身全部的功能卻仍不能滿足你對報表的特殊要求時才請使用 Excel 輸出報表。很明顯&#xff0c;使用 Excel 輸出…

php+mysql投票代碼_PHP+jQuery+MySql實現紅藍投票功能

本文是一篇綜合知識應用類文章&#xff0c;需要您具備PHP、jQuery、MySQL以及html和css方面的基本知識。本文在《PHPMySqljQuery實現的“頂”和“踩”投票功能》一文基礎上做了適當改進&#xff0c;共用了數據表&#xff0c;您可以先點擊了解這篇文章。HTML我們需要在頁面中展示…

numpy 最大值_第 85 天:NumPy 統計函數

數學統計在我們的程序當中特別是數據分析當中是必不可少的一部分&#xff0c;本文就來介紹一下 NumPy 常見的統計函數。最大值與最小值numpy.amin()用于計算數組中的元素沿指定軸的最小值。可以通過 axis 參數傳入坐標軸來指定統計的軸&#xff0c;當指定 axis 時&#xff0c;a…

java中如何實現變量可配置_Java基礎-如何配置環境變量

Java環境變量詳細教程第一步、打開電腦環境變量設置窗口以Win10系統為例子。在桌面找到此電腦&#xff0c;右鍵此電腦— —>屬性&#xff0c;點擊屬性— —>點擊左側高級系統設置點擊高級系統設置點擊環境變量第二步、新建JAVA_HOME點擊系統變量中的新建,出現輸入框&…

python三引號解析_[宜配屋]聽圖閣

和C語言一樣&#xff0c;引號屬于特殊功能字符&#xff0c;不能夠像普通字符那樣直接通過print打印&#xff0c;需要進行一些處理&#xff0c;比如說反斜杠轉義等。這里介紹幾種打印三引號的方法&#xff0c;希望對需要的朋友有用。1、第一中方法比較簡單&#xff0c;直接使用三…

abaqus python 建立節點集合_在Python中創建Abaqus集

我想用Python在Abaqus中創建一個帶邊的幾何集。我不會事先知道邊的數目。嘗試將邊放入數組中&#xff0c;然后創建集合。你知道嗎myEdgesForSet []for i in range(0, len(mdb.models[Model].parts[Part].edges)):if something in mdb.models[Model].parts[Part].edges[i].feat…

java類默認訪問權限_Java的四種訪問權限

? 所謂訪問權限&#xff0c;指的就是本類中的成員變量、成員方法對其他類的可見性?試想一想&#xff0c;當我們修改一個非常龐大的項目時&#xff0c;如果所有變量和方法都是公共權限&#xff0c;那么后端中任何類都有權限去修改它的變量和方法&#xff0c;很有可能修改后就導…

java 數組 反射_【譯】10. Java反射——數組

用Java反射來處理數組有時候是技巧性很強的。特別是如果你需要獲取一個給定類型的數組的Class對象&#xff0c;像int[ ]等。本文將講述怎么用Java反射來創建數組和獲取數組的Class對象。下面是所涵蓋的主題列表&#xff1a;java.lang.reflect.ArrayCreating ArraysAccessing Ar…

定時執行java程序_如何讓Java程序定時運行

由于項目開發的需要&#xff0c;必須實現讓一個Java程序定時運行。比如&#xff0c;我的項目中&#xff0c;有一個網絡蜘蛛&#xff0c;需要從互聯網上抓取數據&#xff0c;與其配合&#xff0c;有另一個程序來對新抓取的頁面進行索引的創建&#xff0c;由于數據源更新頻率不高…