日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql查询时,offset过大影响性能的原因与优化方法

發布時間:2025/3/15 数据库 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql查询时,offset过大影响性能的原因与优化方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

遇到的問題

我們大家都知道,mysql查詢使用select命令,配合limit,offset參數可以讀取指定范圍的記錄,但是offset過大影響查詢性能的原因及優化方法,這次工作中因為要導出40W的數據遇到這個offset過大的問題,遍歷寫入excel的時間花了2個多小時。


準備測試數據表及數據

1、創建表

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)

分析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) 當offset較小時,查詢速度很快,效率較高。

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) 當offset很大時,會出現效率問題,隨著offset的增大,執行效率下降。

分析影響性能原因

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

因為數據表是InnoDB,根據InnoDB索引的結構,查詢過程為:
  • 通過二級索引查到主鍵值(找出所有gender=1的id)。
  • 再根據查到的主鍵值通過主鍵索引找到相應的數據塊(根據id找出對應的數據塊內容)。
  • 根據offset的值,查詢300001次主鍵索引的數據,最后將之前的300000條丟棄,取出最后1條。

    所以,mysql查詢時,offset過大影響性能的原因是多次通過主鍵索引訪問數據塊的I/O操作,如下圖。

InnoDB與MyISAM引擎索引結構對比圖

InnoDB有這個問題,而MYISAM索引結構與InnoDB不同,二級索引都是直接指向數據塊的,因此沒有此問題。

優化方法

根據上面的分析,我們知道查詢所有字段會導致主鍵索引多次訪問數據塊造成的I/O操作。

因此我們先查出偏移后的主鍵,再根據主鍵索引查詢數據塊的所有內容即可優化。

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) 所以最后我通過這個方式查詢數據,百萬級的數據基本都是毫秒級別的查詢出結果,40W數據寫入excel時間從2個多小時優化成20分鐘,滿滿的成就感哈。

參考文章:

  • 轉載from:https://blog.csdn.net/fdipzone/article/details/72793837
  • sefault:https://segmentfault.com/p/1210000008951080/read
  • 轉載于:https://blog.51cto.com/onebig/2124954

    總結

    以上是生活随笔為你收集整理的mysql查询时,offset过大影响性能的原因与优化方法的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。