久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

mysql查詢時(shí)offset過大影響性能的原因是什么

共計(jì) 5282 個(gè)字符,預(yù)計(jì)需要花費(fèi) 14 分鐘才能閱讀完成。

這篇文章主要介紹了 mysql 查詢時(shí) offset 過大影響性能的原因是什么,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓丸趣 TV 小編帶著大家一起了解一下。

準(zhǔn)備測(cè)試數(shù)據(jù)表及數(shù)據(jù)

1. 創(chuàng)建表

CREATE TABLE `member` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `name` varchar(10) NOT NULL COMMENT  姓名 ,
 `gender` tinyint(3) unsigned NOT NULL COMMENT  性別 ,
 PRIMARY KEY (`id`),
 KEY `gender` (`gender`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2. 插入 1000000 條記錄

?php
$pdo = new PDO( mysql:host=localhost;dbname=user , root , 
for($i=0; $i 1000000; $i++){ $name = substr(md5(time().mt_rand(000,999)),0,10);
 $gender = mt_rand(1,2);
 $sqlstr =  insert into member(name,gender) values(.$name. , .$gender.) 
 $stmt = $pdo- prepare($sqlstr);
 $stmt- execute();
mysql  select count(*) from member;
+----------+
| count(*) |
+----------+
| 1000000 |
+----------+
1 row in set (0.23 sec)

3. 當(dāng)前數(shù)據(jù)庫(kù)版本

mysql  select version();
+-----------+
| version() |
+-----------+
| 5.6.24 |
+-----------+
1 row in set (0.01 sec)

分析 offset 過大影響性能的原因

1.offset 較小的情況

mysql  select * from member where gender=1 limit 10,1;
+----+------------+--------+
| id | name | gender |
+----+------------+--------+
| 26 | 509e279687 | 1 |
+----+------------+--------+
1 row in set (0.00 sec)
mysql  select * from member where gender=1 limit 100,1;
+-----+------------+--------+
| id | name | gender |
+-----+------------+--------+
| 211 | 07c4cbca3a | 1 |
+-----+------------+--------+
1 row in set (0.00 sec)
mysql  select * from member where gender=1 limit 1000,1;
+------+------------+--------+
| id | name | gender |
+------+------------+--------+
| 1975 | e95b8b6ca1 | 1 |
+------+------------+--------+
1 row in set (0.00 sec)

當(dāng) offset 較小時(shí),查詢速度很快,效率較高。 

2.offset 較大的情況

mysql  select * from member where gender=1 limit 100000,1;
+--------+------------+--------+
| id | name | gender |
+--------+------------+--------+
| 199798 | 540db8c5bc | 1 |
+--------+------------+--------+
1 row in set (0.12 sec)
mysql  select * from member where gender=1 limit 200000,1;
+--------+------------+--------+
| id | name | gender |
+--------+------------+--------+
| 399649 | 0b21fec4c6 | 1 |
+--------+------------+--------+
1 row in set (0.23 sec)
mysql  select * from member where gender=1 limit 300000,1;
+--------+------------+--------+
| id | name | gender |
+--------+------------+--------+
| 599465 | f48375bdb8 | 1 |
+--------+------------+--------+
1 row in set (0.31 sec)

當(dāng) offset 很大時(shí),會(huì)出現(xiàn)效率問題,隨著 offset 的增大,執(zhí)行效率下降。 

分析影響性能原因

select * from member where gender=1 limit 300000,1;

因?yàn)閿?shù)據(jù)表是 InnoDB,根據(jù) InnoDB 索引的結(jié)構(gòu),查詢過程為:

通過二級(jí)索引查到主鍵值(找出所有 gender= 1 的 id)。

再根據(jù)查到的主鍵值通過主鍵索引找到相應(yīng)的數(shù)據(jù)塊(根據(jù) id 找出對(duì)應(yīng)的數(shù)據(jù)塊內(nèi)容)。

根據(jù) offset 的值,查詢 300001 次主鍵索引的數(shù)據(jù),最后將之前的 300000 條丟棄,取出最后 1 條。

不過既然二級(jí)索引已經(jīng)找到主鍵值,為什么還需要先用主鍵索引找到數(shù)據(jù)塊,再根據(jù) offset 的值做偏移處理呢?

如果在找到主鍵索引后,先執(zhí)行 offset 偏移處理,跳過 300000 條,再通過第 300001 條記錄的主鍵索引去讀取數(shù)據(jù)塊,這樣就能提高效率了。

如果我們只查詢出主鍵,看看有什么不同

mysql  select id from member where gender=1 limit 300000,1;
+--------+
| id |
+--------+
| 599465 |
+--------+
1 row in set (0.09 sec)

很明顯,如果只查詢主鍵,執(zhí)行效率對(duì)比查詢?nèi)孔侄危泻艽蟮奶嵘?nbsp;

推測(cè)

只查詢主鍵的情況

因?yàn)槎?jí)索引已經(jīng)找到主鍵值,而查詢只需要讀取主鍵,因此 mysql 會(huì)先執(zhí)行 offset 偏移操作,再根據(jù)后面的主鍵索引讀取數(shù)據(jù)塊。

需要查詢所有字段的情況

因?yàn)槎?jí)索引只找到主鍵值,但其他字段的值需要讀取數(shù)據(jù)塊才能獲取。因此 mysql 會(huì)先讀出數(shù)據(jù)塊內(nèi)容,再執(zhí)行 offset 偏移操作,最后丟棄前面需要跳過的數(shù)據(jù),返回后面的數(shù)據(jù)。 

證實(shí)

InnoDB 中有 buffer pool,存放最近訪問過的數(shù)據(jù)頁(yè),包括數(shù)據(jù)頁(yè)和索引頁(yè)。

為了測(cè)試,先把 mysql 重啟,重啟后查看 buffer pool 的內(nèi)容。

mysql  select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in(primary , gender) and TABLE_NAME like  %member%  group by index_name;
Empty set (0.04 sec)

可以看到,重啟后,沒有訪問過任何的數(shù)據(jù)頁(yè)。

查詢所有字段,再查看 buffer pool 的內(nèi)容

mysql  select * from member where gender=1 limit 300000,1;
+--------+------------+--------+
| id | name | gender |
+--------+------------+--------+
| 599465 | f48375bdb8 | 1 |
+--------+------------+--------+
1 row in set (0.38 sec)
mysql  select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in(primary , gender) and TABLE_NAME like  %member%  group by index_name;
+------------+----------+
| index_name | count(*) |
+------------+----------+
| gender | 261 |
| PRIMARY | 1385 |
+------------+----------+
2 rows in set (0.06 sec)

可以看出,此時(shí) buffer pool 中關(guān)于 member 表有 1385 個(gè)數(shù)據(jù)頁(yè),261 個(gè)索引頁(yè)。 

重啟 mysql 清空 buffer pool,繼續(xù)測(cè)試只查詢主鍵

mysql  select id from member where gender=1 limit 300000,1;
+--------+
| id |
+--------+
| 599465 |
+--------+
1 row in set (0.08 sec)
mysql  select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in(primary , gender) and TABLE_NAME like  %member%  group by index_name;
+------------+----------+
| index_name | count(*) |
+------------+----------+
| gender | 263 |
| PRIMARY | 13 |
+------------+----------+
2 rows in set (0.04 sec)

可以看出,此時(shí) buffer pool 中關(guān)于 member 表只有 13 個(gè)數(shù)據(jù)頁(yè),263 個(gè)索引頁(yè)。因此減少了多次通過主鍵索引訪問數(shù)據(jù)塊的 I / O 操作,提高執(zhí)行效率。

因此可以證實(shí),mysql 查詢時(shí),offset 過大影響性能的原因是多次通過主鍵索引訪問數(shù)據(jù)塊的 I / O 操作。(注意,只有 InnoDB 有這個(gè)問題,而 MYISAM 索引結(jié)構(gòu)與 InnoDB 不同,二級(jí)索引都是直接指向數(shù)據(jù)塊的,因此沒有此問題)。 

InnoDB 與 MyISAM 引擎索引結(jié)構(gòu)對(duì)比圖

這里寫圖片描述

優(yōu)化方法

根據(jù)上面的分析,我們知道查詢所有字段會(huì)導(dǎo)致主鍵索引多次訪問數(shù)據(jù)塊造成的 I / O 操作。

因此我們先查出偏移后的主鍵,再根據(jù)主鍵索引查詢數(shù)據(jù)塊的所有內(nèi)容即可優(yōu)化。

mysql  select a.* from member as a inner join (select id from member where gender=1 limit 300000,1) as b on a.id=b.id;
+--------+------------+--------+
| id | name | gender |
+--------+------------+--------+
| 599465 | f48375bdb8 | 1 |
+--------+------------+--------+
1 row in set (0.08 sec)

附:MYSQL limit,offset 區(qū)別

SELECT
 keyword
 keyword_rank
WHERE
 advertiserid= 59 
order by
 keyword
LIMIT 2 OFFSET 1;

比如這個(gè) SQL,limit 后面跟的是 2 條數(shù)據(jù),offset 后面是從第 1 條開始讀取

SELECT
 keyword
 keyword_rank
WHERE
 advertiserid= 59 
ORDER BY
 keyword
LIMIT 2 ,1;

而這個(gè) SQL,limit 后面是從第 2 條開始讀,讀取 1 條信息。

這兩個(gè)千萬(wàn)別搞混哦。

感謝你能夠認(rèn)真閱讀完這篇文章,希望丸趣 TV 小編分享的“mysql 查詢時(shí) offset 過大影響性能的原因是什么”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持丸趣 TV,關(guān)注丸趣 TV 行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!

正文完
 
丸趣
版權(quán)聲明:本站原創(chuàng)文章,由 丸趣 2023-08-04發(fā)表,共計(jì)5282字。
轉(zhuǎn)載說(shuō)明:除特殊說(shuō)明外本站除技術(shù)相關(guān)以外文章皆由網(wǎng)絡(luò)搜集發(fā)布,轉(zhuǎn)載請(qǐng)注明出處。
評(píng)論(沒有評(píng)論)
主站蜘蛛池模板: 镇宁| 洮南市| 集安市| 洛隆县| 越西县| 吴旗县| 梧州市| 怀宁县| 合江县| 定陶县| 聂荣县| 洛阳市| 宁城县| 嘉善县| 汝城县| 淅川县| 宣城市| 湘潭市| 宁河县| 尖扎县| 丹棱县| 昌黎县| 韶关市| 镇江市| 寿宁县| 安阳县| 府谷县| 霍邱县| 天峨县| 桦南县| 舞钢市| 苏尼特左旗| 林芝县| 长垣县| 玉龙| 开封县| 屏山县| 鄱阳县| 通海县| 平阳县| 济阳县|