前言

mysql查询使用select命令,配合limit,offset参数可以读取指定范围的记录。本文将介绍mysql查询时,offset过大影响性能的原因及优化方法。

准备测试数据表及数据

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条记录

$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.当前数据库版本

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)

当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条。

不过既然二级索引已经找到主键值,为什么还需要先用主键索引找到数据块,再根据offset的值做偏移处理呢?

如果在找到主键索引后,先执行offset偏移处理,跳过300000条,再通过第300001条记录的主键索引去读取数据块,这样就能提高效率了。

如果我们只查询出主键,看看有什么不同

mysql> select id from member where gender=1 limit 300000,1;

+--------+

| id |

+--------+

| 599465 |

+--------+

1 row in set (0.09 sec)

很明显,如果只查询主键,执行效率对比查询全部字段,有很大的提升。

推测

只查询主键的情况

因为二级索引已经找到主键值,而查询只需要读取主键,因此mysql会先执行offset偏移操作,再根据后面的主键索引读取数据块。

需要查询所有字段的情况

因为二级索引只找到主键值,但其他字段的值需要读取数据块才能获取。因此mysql会先读出数据块内容,再执行offset偏移操作,最后丢弃前面需要跳过的数据,返回后面的数据。

证实

InnoDB中有buffer pool,存放最近访问过的数据页,包括数据页和索引页。

为了测试,先把mysql重启,重启后查看buffer pool的内容。

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)

可以看到,重启后,没有访问过任何的数据页。

查询所有字段,再查看buffer pool的内容

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)

可以看出,此时buffer pool中关于member表有1385个数据页,261个索引页。

重启mysql清空buffer pool,继续测试只查询主键

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)

可以看出,此时buffer pool中关于member表只有13个数据页,263个索引页。因此减少了多次通过主键索引访问数据块的I/O操作,提高执行效率。

因此可以证实,mysql查询时,offset过大影响性能的原因是多次通过主键索引访问数据块的I/O操作。(注意,只有InnoDB有这个问题,而MYISAM索引结构与InnoDB不同,二级索引都是直接指向数据块的,因此没有此问题 )。

InnoDB与MyISAM引擎索引结构对比图

这里写图片描述

优化方法

根据上面的分析,我们知道查询所有字段会导致主键索引多次访问数据块造成的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)

附:MYSQL limit,offset 区别

SELECT

keyword

FROM

keyword_rank

WHERE

advertiserid='59'

order by

keyword

LIMIT 2 OFFSET 1;

比如这个SQL ,limit后面跟的是2条数据,offset后面是从第1条开始读取

SELECT

keyword

FROM

keyword_rank

WHERE

advertiserid='59'

ORDER BY

keyword

LIMIT 2 ,1;

而这个SQL,limit后面是从第2条开始读,读取1条信息。

这两个千万别搞混哦。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

mysqloffset什么意思_mysql查询时offset过大影响性能的原因和优化详解相关推荐

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

    遇到的问题 我们大家都知道,mysql查询使用select命令,配合limit,offset参数可以读取指定范围的记录,但是offset过大影响查询性能的原因及优化方法,这次工作中因为要导出40W的数 ...

  2. mysql limit offset很大_MySQL查询中LIMIT的大offset导致性能低下浅析

    前言 我们大家都知道,mysql查询使用select命令,配合limit,offset参数可以读取指定范围的记录,但是offset过大影响查询性能的原因及优化方法 我们在业务系统中难免少不了分页的需求 ...

  3. mysql索引linke和等于_MySQL之SQL优化详解(三)

    摘要: 致索引失效而转向全表扫描存储引擎不能使用索引中范围条件右边的列mysql在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫描isnull,isnotnull也无法使用索引l ...

  4. mysql ssd 性能测试 写入_MySQL服务器的SSD性能问题分析和测试详解

    [问题] 我们有台HP的服务器,SSD在写IOPS约5000时,%util达到80%以上,那么这块SSD的性能究竟有没有问题,为解决这个问题做了下面测试. [工具] blktrace是linux下用来 ...

  5. java excel中重复数据 事务处理_Java导出excel时合并同一列中相同内容的行思路详解...

    一.有时候导出Excel时需要按类别导出,一大类下好几个小类,小类下又有好几个小小类,就像下图: 要实现这个也不难, 思路如下:按照大类来循环,如上就是按照张江校区.徐汇校区.临港校区三个大类循环,然 ...

  6. java 导出如何合并列_Java导出excel时合并同一列中相同内容的行思路详解

    一.有时候导出Excel时需要按类别导出,一大类下好几个小类,小类下又有好几个小小类,就像下图: 要实现这个也不难, 思路如下:按照大类来循环,如上就是按照张江校区.徐汇校区.临港校区三个大类循环,然 ...

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

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

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

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

  9. CSS3 @media媒体查询 适配不同尺寸设备的响应式布局(清晰详解)

    随着宽屏的不断普及,CSS3出现了@media媒体查询技术 一.了解@Media 相关知识 1.了解Media Queries Media Queries能在不同的条件下使用不同的样式,使页面在不同在 ...

  10. mysql mediumint 长度_mysql字段类型tinyint、smallint、mediumint、int、bigint详解

    mysql建模的过程中,对于优化来讲一个非常重要的点就是字段类型的设置,好的字段类型的设置可以帮助更快的查询数据同时能节约硬盘空间,这对于优化数据库来讲是非常重要的. mysql的字段类型大体来讲分为 ...

最新文章

  1. Windows 2000、XP、XP+进程名描述
  2. 每日一博 - ThreadLocal VS InheritableThreadLocal VS TransmittableThreadLocal
  3. leedcode344. 反转字符串
  4. python合并表格矩阵并排序_在Python中,将多个列的列表排列成一个矩阵
  5. webpack对脚本和样式的处理
  6. usb3.0驱动linux,dwc3 linux usb3.0 driver架构
  7. 无网络访问权限怎么办_老司机教你IPV4无网络访问权限怎么办
  8. hb:一个简单的 http/web bench 工具
  9. 【Paper】英文文章图表规范和文献引用格式
  10. V4 乱码问题总结 v5 也可以参考
  11. 标准nvmexpress控制器驱动下载_NVM Express控制器驱动程序
  12. Google Authenticator(谷歌身份验证器)C#版
  13. 不动点迭代 开平方 Excel演示
  14. Python使用pip安装报错ModuleNotFoundError: No module named ‘pip._internal.cli.main‘的解决方法
  15. 看不到工作组的其他计算机_就这一次,从现实世界的角度去理解计算机领域的知识(给新手)...
  16. vue路由模板是html,vue-router 详解
  17. 已解决NameError: name ‘unichr‘ is not defined
  18. 软件测试 | 白盒的测试方法
  19. 神经平面分布图怎么看,面部神经网络 分布图
  20. freemarker数字显示问题(超过1000会加逗号分隔)

热门文章

  1. c++ 怎么输出保留2位小数的浮点数
  2. 关于div+css布局值得注意的地方
  3. 006 关于大数据的本地模式环境的搭建
  4. 假定CSomething是一个类,执行下面这些语句之后,内存里创建了____个CSomething对象。...
  5. [转载]sed实现直接修改文件内容
  6. hdu 1099 Lottery
  7. Imagej分析所有气泡的粒径
  8. 【学堂在线数据挖掘:理论方法笔记】第八天(4.2)
  9. 红黑树简介与C++应用
  10. linux普通用户配置自己的python环境