0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

为什么分页场景下mysql请求速度非常慢

Android编程精选 来源:掘金 作者:牛牛码特 2021-10-08 14:46 次阅读

来源丨https://juejin.cn/post/6844903939247177741

从一个问题说起五年前在tx的时候,发现分页场景下,mysql请求速度非常慢。数据量只有10w的情况下,select xx from 单机大概2,3秒。我就问我导师为什么,他反问“索引场景,mysql中获得第n大的数,时间复杂度是多少?”

答案的追寻确认场景假设status上面有索引。select * from table where status = xx limit 10 offset 10000。会非常慢。数据量不大的情况就有几秒延迟。

小白作答瞎猜了个log(N),心想找一个节点不就是log(N)。自然而然,导师让我自己去研究。

这一阶段,用了10分钟。

继续解答仔细分析一下,会发现通过索引去找很别扭。因为你不知道前100个数在左子树和右子数的分布情况,所以其是无法利用二叉树的查找特性。通过学习,了解到mysql的索引是b+树。

0c76bb4e-23df-11ec-82a8-dac502259ad0.png

看了这个图,就豁然开朗了。可以直接通过叶子节点组成的链表,以o(n)的复杂度找到第100大的树。但是即使是o(n),也不至于慢得令人发指,是否还有原因。

这一阶段,主要是通过网上查资料,断断续续用了10天。

系统学习这里推荐两本书,一本《MySQL技术内幕 InnoDB存储引擎》,通过他可以对InnoDB的实现机制,如mvcc,索引实现,文件存储会有更深理解。

第二本是《高性能MySQL》,这本书从着手使用层面,但讲得比较深入,而且提到了很多设计的思路。

两本书相结合,反复领会,mysql就勉强能登堂入室了。

这里有两个关键概念:

聚簇索引:包含主键索引和对应的实际数据,索引的叶子节点就是数据节点

辅助索引:可以理解为二级节点,其叶子节点还是索引节点,包含了主键id。

即使前10000个会扔掉,mysql也会通过二级索引上的主键id,去聚簇索引上查一遍数据,这可是10000次随机io,自然慢成哈士奇。这里可能会提出疑问,为什么会有这种行为,这是和mysql的分层有关系,limit offset 只能作用于引擎层返回的结果集。换句话说,引擎层也很无辜,他并不知道这10000个是要扔掉的。以下是mysql分层示意图,可以看到,引擎层和server层,实际是分开的。

直到此时,大概明白了慢的原因。这一阶段,用了一年。

触类旁通此时工作已经3年了,也开始看一些源码。在看完etcd之后,看了些tidb的源码。无论哪种数据库,其实一条语句的查询,是由逻辑算子组成。

逻辑算子介绍 在写具体的优化规则之前,先简单介绍查询计划里面的一些逻辑算子。

DataSource 这个就是数据源,也就是表,select * from t 里面的 t。

Selection 选择,例如 select xxx from t where xx = 5 里面的 where 过滤条件。

Projection 投影, select c from t 里面的取 c 列是投影操作。

Join 连接, select xx from t1, t2 where t1.c = t2.c 就是把 t1 t2 两个表做 Join。

选择,投影,连接(简称 SPJ) 是最基本的算子。其中 Join 有内连接,左外右外连接等多种连接方式。

select b from t1, t2 where t1.c = t2.c and t1.a 》 5 变成逻辑查询计划之后,t1 t2 对应的 DataSource,负责将数据捞上来。上面接个 Join 算子,将两个表的结果按 t1.c = t2.c连接,再按t1.a 》 5做一个 Selection 过滤,最后将 b 列投影。下图是未经优化的表示:

所以说不是mysql不想把limit, offset传递给引擎层,而是因为划分了逻辑算子,所以导致无法直到具体算子包含了多少符合条件的数据。

怎么解决《高性能MySQL》提到了两种方案

方案一

根据业务实际需求,看能否替换为下一页,上一页的功能,特别在iosandroid端,以前那种完全的分页是不常见的。这里是说,把limit, offset,替换为》辅助索引(即搜索条件)id的方式。该id再调用时,需要返回给前端。

方案二

正面刚。这里介绍一个概念:索引覆盖:当辅助索引查询的数据,只有id和辅助索引本身,那么就不必再去查聚簇索引。

思路如下:select xxx,xxx from in (select id from table where second_index = xxx limit 10 offset 10000) 这句话是说,先从条件查询中,查找数据对应的数据库唯一id值,因为主键在辅助索引上就有,所以不用回归到聚簇索引的磁盘去拉取。再通过这些已经被limit出来的10个主键id,去查询聚簇索引。这样只会十次随机io。在业务确实需要用分页的情况下,使用该方案可以大幅度提高性能。通常能满足性能要求。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据
    +关注

    关注

    8

    文章

    6511

    浏览量

    87582
  • SQL
    SQL
    +关注

    关注

    1

    文章

    737

    浏览量

    43458

原文标题:分页场景(limit,offset)为什么会慢?

文章出处:【微信号:AndroidPush,微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    STM32F429做的PIL仿真速度非常的原因?

    ,但是速度非常。不知道是否STM32F429的参数设定有问题。有没有哪位大神做过相关的仿真。补充:仿真中控制器开关频率是5000khz,采样时间为5e^-5s。 先谢谢了!
    发表于 04-11 07:28

    STM32H743 IO速度慢是什么原因造成的?

    STM32H743 IO速度慢,实际能到多少.IO翻转速度只有16M,读一个IO要很多个时钟周期,是都这样的吗。
    发表于 03-21 07:16

    M481系列KEIL选择ARM5编译器 ,编译速度非常怎么解决?

    M481系列,如果KEIL选择ARM5编译器 ,编译速度非常
    发表于 01-16 06:51

    mybatis逻辑分页和物理分页的区别

    这两种分页方式的区别。 逻辑分页是在数据库中执行查询时使用的一种分页方式。这种方式是通过在查询语句中添加LIMIT或OFFSET关键字来限制结果集的大小和偏移量来实现的。常见的逻辑分页
    的头像 发表于 12-03 14:54 440次阅读

    MySQL数据库基础知识

    的基础知识,包括其架构、数据类型、表操作、查询语句和数据导入导出等方面。 MySQL 数据库架构 MySQL 数据库由多个组件组成,包括服务器、存储引擎和客户端等。MySQL 服务器是数据库的核心,它负责处理客户端的
    的头像 发表于 11-21 11:09 497次阅读

    redis与mysql的区别

    对的形式,可以是字符串、哈希、列表、集合、有序集合等数据结构。这种数据模型使得Redis非常适合用于缓存、消息队列、计数器等场景MySQL是一种关系型数据库,采用表格的形式组织数据,每个表包含多个行和列。它支持复杂的数据查询
    的头像 发表于 11-16 11:21 467次阅读

    arduino驱动舵机速度能否一些?

    arduino驱动舵机速度太快,能不能一些,就是占空比调节的指定宽度有个时间设置的函数有吗?比如0度到90度我需要转动3秒完成,但是直接驱动到90度速度太快了半秒就到90度了
    发表于 11-08 06:03

    如何将数据从MySQL迁移到Influxdb中

    如果以前是将时序数据存放在MySQL,现在为了获取更好的性能和使用可视化工具,我们需要将数据从MySQL迁移到Influxdb中。 这看起来是一个常见场景,经过一番查阅,发现了
    的头像 发表于 11-02 10:54 642次阅读

    高并发场景请求合并

    我们在服务器端把请求合并,只发出一条SQL查询数据库,数据库返回后,服务器端处理返回数据,根据一个唯一请求ID,把数据分组,返回给对应用户。
    的头像 发表于 10-09 16:05 189次阅读
    高并发<b class='flag-5'>场景</b>下<b class='flag-5'>请求</b>合并

    mysql数据库索引失效的10种场景

    今天就跟大家一起聊聊,mysql数据库索引失效的10种场景,给曾经踩过坑,或者即将要踩坑的朋友们一个参考。 1. 准备工作 所谓空口无凭,如果我直接把索引失效的这些场景丢出来,可能没有任何说服力
    的头像 发表于 10-07 16:31 903次阅读
    <b class='flag-5'>mysql</b>数据库索引失效的10种<b class='flag-5'>场景</b>

    如何在Rust中连接和使用MySQL数据库

    MySQL是一个广泛使用的关系型数据库,Rust作为一门相对较新的系统级编程语言,具有C语言般的高性能、安全、并发等特性,因此与MySQL一起使用是一种非常有趣的选择。在本教程中,我们将手把手地展示
    的头像 发表于 09-30 17:05 912次阅读

    SQLite和MySQL区别

    MySQL时,用户要考虑很多方面的区别。 1.适用范围 SQLite比较适合在少量并发用户、轻负载的场景下使用,一般用于嵌入式系统、移动端等小规模应用;而MySQL则适合大型的、高并发的应用
    的头像 发表于 08-28 17:09 2623次阅读

    M481系列如果KEIL选择ARM5编译器 ,编译速度非常怎么解决?

    M481系列,如果KEIL选择ARM5编译器 ,编译速度非常
    发表于 08-25 06:00

    MySQL并发Replace into导致死锁场景简析

    在之前的文章 #issue 68021 MySQL unique check 问题中, 我们已经介绍了在 MySQL 里面, 由于唯一键的检查(unique check), 导致 MySQL 在 Read Commit 隔离级别
    的头像 发表于 06-13 10:56 618次阅读
    <b class='flag-5'>MySQL</b>并发Replace into导致死锁<b class='flag-5'>场景</b>简析

    图文详解Linux分页机制

    分页机制是 80x86 内存管理机制的第二种机制,分段机制用于把虚拟地址转换为线性地址,而分页机制用于把线性地址转换为物理地址。
    发表于 05-30 09:10 291次阅读
    图文详解Linux<b class='flag-5'>分页</b>机制