遇到的问题

我们大家都知道,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分钟,满满的成就感哈。

参考文章

  1. 转载from:https://blog.csdn.net/fdipzone/article/details/72793837
  2. sefault:https://segmentfault.com/p/1210000008951080/read

转载于:https://blog.51cto.com/onebig/2124954

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

  1. MySQL查询中LIMIT的大offset导致性能低下浅析

    这篇文章主要给大家介绍了关于MySQL查询中LIMIT的大offset导致性能低下的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起 ...

  2. MySQL查询时记录行号rownum MySQL查询显示行号MySQL查询显示行号MySQL流水号自MySQL自增行号

    MySQL查询时记录行号rownum MySQL查询显示行号MySQL查询显示行号MySQL流水号自MySQL自增行号 一.前言 Oracle中有rownum,实现查询的时候记录行号,MySQL中没有 ...

  3. mysql大小写区分_详解MySQL查询时区分字符串中字母大小写的方法

    如果你在mysql有唯一约束的列上插入两行值'A'和'a',Mysql会认为它是相同的,而在oracle中就不会.就是mysql默认的字段值不区分大小写?这点是比较令人头痛的事.直接使用客户端用sql ...

  4. 上传文件时$_FILES为空,可能的原因及解决方法

    上传文件时$_FILES为空,可能的原因及解决方法 参考文章: (1)上传文件时$_FILES为空,可能的原因及解决方法 (2)https://www.cnblogs.com/i6010/articl ...

  5. SSH连接时出现Host key verification failed的原因及解决方法

    SSH连接时出现Host key verification failed的原因及解决方法 参考文章: (1)SSH连接时出现Host key verification failed的原因及解决方法 ( ...

  6. MySQL:为什么用limit时,offset很大会影响性能

    点击上方"朱小厮的博客",选择"设为星标" 后台回复"加群"加入公众号专属技术群 来源:rrd.me/fe8TT 一,前言 首先说明一下My ...

  7. mysql id用什么类型_mysql 证明为什么用limit时,offset很大会影响性能

    首先说明一下MySQL的版本: mysql> select version(); +-----------+ | version() | +-----------+ | 5.7.17 | +-- ...

  8. oschina mysql limit_MySQL 用 limit 为什么会影响性能?

    点击上方"武培轩",选择"设为星标" 技术文章第一时间送达! 一,前言 首先说明一下MySQL的版本: mysql> select version();+ ...

  9. MySQL查询时指定使用索引

    在MySQL中,可以通过指定查询使用的索引来提高查询性能和优化查询执行计划.以下是一些常见的场景,可能需要考虑指定查询使用的索引: 查询性能问题:当一个查询在大表上运行缓慢时,可以考虑为该查询指定合适 ...

最新文章

  1. spark任务优先级设置:spark.yarn.priority
  2. SSD: Signle Shot Detector 用于自然场景文字检测
  3. 在 ubuntu 上编译 qtopia-2.2.0问题
  4. [转]打造自己的LINQ Provider(上):Expression Tree揭秘
  5. java heap_javaHeap的组成及GC监控
  6. php windows环境 安装 Apache-apollo + phpMQTT 实现发送 MQTT
  7. kali免杀工具shellter
  8. 如何将大硬盘对拷到小硬盘
  9. mathorcup历年优秀论文阿里云盘
  10. scheme语言编写运行
  11. 用python画写轮眼_创意scratch编程课:火影经典忍术,宇智波佐助的写轮眼!
  12. 有内鬼,终止换脸!用Landmarks Debug找出不老实的脸。
  13. 【汇正财经】什么是股权结构?
  14. SCSS迷你书(上)
  15. Visual2022安装步骤社区版,专业版or企业版安装(附注册码)(没有桌面图标的解决方法)
  16. 进程的概念与基本介绍
  17. AS打包的应用安装时解析包错误或没有签名
  18. WEB安全之:SQL Injection--DVWA环境测试
  19. node.js毕业设计安卓基于Android的超市会员管理系统开发(程序+APP+LW)
  20. NY8B062D 九齐单片机之ADC芯片

热门文章

  1. 洛谷 P1219 ---- 八皇后
  2. 关于eclipse web项目认不到用户库的问题
  3. python tfidf特征变换_Spark MLlib机器学习开发指南(4)--特征提取--TF-IDF
  4. linux系统终端more,一篇文章让你学透Linux系统中的more命令
  5. jdbc是java语言编写的类和接口_JDBC——Java语言连接数据库的标准
  6. appSettings 配置mysql_app.config数据库配置字符串的三种取法
  7. 晓庄学院计算机科学分数,南京晓庄学院计算机单招分数
  8. 计算机应用技术自我分析,计算机应用*个人自我鉴定
  9. linux使用u盘的过程是,图文详解Linux下使用U盘的方法
  10. java this() super()_java中的this和super