iis服务器助手广告
返回顶部
首页 > 资讯 > 精选 >千万级用户系统SQL调优的示例分析
  • 427
分享到

千万级用户系统SQL调优的示例分析

2023-06-29 09:06:55 427人浏览 独家记忆
摘要

这篇文章主要介绍了千万级用户系统sql调优的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。用户日活百万级,注册用户千万级,而且若还没有进行分库分表,则该DB里的用户表

这篇文章主要介绍了千万级用户系统sql调优的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

用户日活百万级,注册用户千万级,而且若还没有进行分库分表,则该DB里的用户表可能就一张,单表上千万的用户数据。

千万级用户系统SQL调优的示例分析

某系统专门通过各种条件筛选大量用户,接着对那些用户去推送一些消息:

  • 一些促销活动消息

  • 让你办会员卡的消息

  • 告诉你有一个特价商品的消息

通过一些条件筛选出大量用户,针对这些用户做推送,该过程较耗时-筛选用户过程。

用户日活百万级,注册用户千万级,而且若还没有进行分库分表,则该DB里的用户表可能就一张,单表上千万的用户数据。

对运营系统筛选用户的SQL:

SELECT id, name FROM users WHERE id IN (  SELECT user_id   FROM users_extent_info   WHERE latest_login_time < xxxxx)

一般存储用户数据的表会分为两张表:

  • 存储用户的核心数据,如id、name、昵称、手机号之类的信息,也就是上面SQL语句里的users表

  • 存储用户的一些拓展信息,比如说家庭住址、兴趣爱好、最近一次登录时间之类的,即users_extent_info

有个子查询,里面针对用户的拓展信息表,即users_extent_info查下最近一次登录时间<某个时间点的用户,可以查询最近才登录过的用户,也可查询很长时间未登录的用户,然后给他们发push,无论哪种场景, 该SQL都适用。

然后在外层查询,用id IN子句查询 id 在子查询结果范围里的users表的所有数据,此时该SQL突然会查出很多数据,可能几千、几万、几十万,所以执行此类SQL前,都会先执行count:

SELECT COUNT(id)FROM usersWHERE id IN (    SELECT user_id    FROM users_extent_info    WHERE latest_login_time < xxxxx    )

然后内存里做个小批量,多批次读取数据的操作,比如判断如果在1000条以内,那么就一下子读取出来,若超过1000条,可通过LIMIT语句,每次就从该结果集里查1000条数据,查1000条就做次批量PUSH,再查下一波1000条。

就是在千万级数据量大表场景下,上面SQL直接轻松跑出来耗时几十s,不优化不行!

今天咱们继续来看这个千万级用户场景下的运营系统SQL调优案例,上次已经给大家说了一下业务背景 以及SQL,这个SQL就是如下的一个:

SELECT COUNT(id) FROM users WHERE id IN (SELECT user_id FROM users_extent_info WHERE latest_login_time < xxxxx)

系统运行时,先COUNT查该结果集有多少数据,再分批查询。然而COUNT在千万级大表场景下,都要花几十s。实际上每个不同的MySQL版本都可能会调整生成执行计划的方式。

通过:

EXPLaiN SELECT COUNT(id) FROM users WHERE id IN (  SELECT user_id   FROM users_extent_info   WHERE latest_login_time < xxxxx)

如下执行计划是为了调优,在测试环境的单表2万条数据场景,即使是5万条数据,当时这个SQL都跑了十多s,注意执行计划里的数据量

执行计划里的第三行

先子查询,针对users_extent_info,使用idx_login_time索引,做了range类型的索引范围扫描,查出4561条数据,没有做额外筛选,所以filtered=100%。

MATERIALIZED:这里把子查询的4561条数据代表的结果集进行了物化,物化成了一个临时表,这个临时表物化,一定是会把4561条数据临时落到磁盘文件里去的,这过程很慢。

第二条执行计划

针对users表做了一个全表扫描,在全表扫描的时候扫出来49651条数据,Extra=Using join buffer,此处居然在执行join。

执行计划里的第一条

针对子查询产出的一个物化临时表,即做了个全表查询,把里面的数据都扫描了一遍。

为何对这临时表进行全表扫描?让users表的每条数据都和物化临时表里的数据进行join,所以针对users表里的每条数据,只能是去全表扫描一遍物化临时表,从物化临时表里确认哪条数据和他匹配,才能筛选出一条结果。

第二条执行计划的全表扫描结果表明一共扫到49651条,但全表扫描过程中,因为和物化临时表执行join,而物化临时表里就4561条数据,所以最终第二条执行计划的filtered=10%,即最终从users表里也筛选出4000多条数据。

到底为什么慢

| id | select_type | table | type | key | rows | filtered | Extra |+----+-------------+-------+------------+-------+---------------+----------+---------+---| 1 | SIMPLE | | ALL | NULL | NULL | 100.00 | NULL || 1 | SIMPLE | users | ALL | NULL | 49651 | 10.00 | Using where; Using join buffer(Block Nested Loop) || 2 | MATERIALIZED | users_extent_info | range | idx_login_time | 4561 | 100.00 | NULL |

先执行了子查询查出4561条数据,物化成临时表,接着对users主表全表扫描,扫描过程把每条数据都放到物化临时表里做全表扫描,本质在做join

对子查询的结果做了一次物化临时表,落地磁盘,接着还全表扫描users表,每条数据居然跑到一个没有索引的物化临时表里,又做了一次全表扫描找匹配的数据。

users表的全表扫描耗时吗?

users表的每一条数据跑到物化临时表里做全表扫描耗时吗?

所以必然非常慢,几乎用不到索引。为什么Mysql会这样呢?

执行完上述SQL的EXPLAIN命令,看到执行计划之后,再执行:

show warnings

显示出:

 select count( d2. users . user_id `) AS COUNT(users.user_id)`from d2 . users users semi join xxxxxx

注意: semi join ,mysql在这里,生成执行计划的时候,自动就把一个普通IN子句,“优化”成基于semi join来进行IN+子查询的操作。那对users表不是全表扫描了吗?对users表里每条数据,去对物化临时表全表扫描做semi join,无需将users表里的数据真的跟物化临时表里的数据join。只要users表里的一条数据,在物化临时表能找到匹配数据,则users表里的数据就会返回,这就是semi join,用来做筛选。

所以就是semi join和物化临时表导致的慢题,那怎么优化?

做个实验

执行:

SET optimizer_switch='semijoin=off'

关闭半连接优化,再执行EXPLAIN发现恢复为正常状态:

有个SUBQUERY子查询,基于range方式去扫描索引,搜索出4561条数据
接着有个PRIMARY类型主查询,直接基于id这个PRIMARY主键聚簇索引去执行的搜索
然后再把这个SQL语句真实跑一下看看,性能竟然提升了几十倍,仅100多ms。
所以,其实反而是MySQL自动执行的semi join半连接优化,导致了极差性能,关闭即可。

生产环境当然不能随意更改这些设置,于是想了多种办法尝试去修改SQL语句的写法,在不影响其语义情况下,尽可能改变SQL语句的结构和格式,

最终尝试出如下写法:

SELECT COUNT(id)FROM usersWHERE (    id IN (        SELECT user_id        FROM users_extent_info        WHERE latest_login_time < xxxxx)         OR    id IN (        SELECT user_id        FROM users_extent_info        WHERE latest_login_time < -1))

上述写法下,WHERE语句的OR后面的第二个条件,根本不可能成立,因为没有数据的latest_login_time<-1,所以那不会影响SQL业务语义,但改变SQL后,执行计划也会变,就没有再semi join优化了,而是常规地用了子查询,主查询也是基于索引,同样达到几百ms 性能优化

所以最核心的,还是看懂SQL执行计划,分析慢的原因,尽量避免全表扫描,务必用上索引。

感谢你能够认真阅读完这篇文章,希望小编分享的“千万级用户系统SQL调优的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网精选频道,更多相关知识等着你来学习!

--结束END--

本文标题: 千万级用户系统SQL调优的示例分析

本文链接: https://www.lsjlt.com/news/323737.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 千万级用户系统SQL调优的示例分析
    这篇文章主要介绍了千万级用户系统SQL调优的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。用户日活百万级,注册用户千万级,而且若还没有进行分库分表,则该DB里的用户表...
    99+
    2023-06-29
  • 千万级用户系统SQL调优实战分享
    用户日活百万级,注册用户千万级,而且若还没有进行分库分表,则该DB里的用户表可能就一张,单表上千万的用户数据。 某系统专门通过各种条件筛选大量用户,接着对那些用户去推送一些消息: ...
    99+
    2024-04-02
  • SQL调优的示例分析
    这篇文章主要为大家展示了“SQL调优的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“SQL调优的示例分析”这篇文章吧。环境:Microsoft SQL Server 2016 (SP2-...
    99+
    2023-06-05
  • oracle的sql调优的示例分析
    oracle的sql调优的示例分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。 查询某个session造成lmode为3的...
    99+
    2024-04-02
  • oracle系统用户的示例分析
    这篇文章主要介绍oracle系统用户的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!oracle中的帐户分为两类:一类是必需的帐户,一类是存储各种应用的帐户 用户名...
    99+
    2024-04-02
  • MySQL数据库千万级数据查询和存储的示例分析
    这篇文章主要介绍MySQL数据库千万级数据查询和存储的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!百万级数据处理方案数据存储结构设计表字段设计表字段 not null,因为 null 值很难查询优化且占用额...
    99+
    2023-06-15
  • Fedora用户占据LINUX系统的示例分析
    本篇文章为大家展示了Fedora用户占据LINUX系统的示例分析,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Fedora用户已经泛滥了,这里介绍Fedora用户群体使用Linux系统的统计,让大家...
    99+
    2023-06-16
  • Mysql百万级数据迁移的示例分析
    这篇文章将为大家详细讲解有关Mysql百万级数据迁移的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。     ...
    99+
    2024-04-02
  • sql server性能调优 I/O开销的示例分析
    这篇文章主要介绍sql server性能调优 I/O开销的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一.概述IO 内存是sql server最重要的资源,数据从磁盘加载到...
    99+
    2024-04-02
  • Linux系统中内核调试的示例分析
    这篇文章主要介绍了Linux系统中内核调试的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。调试是软件开发过程中一个必不可少的环节,在 Linux 内核开发的过程中也不...
    99+
    2023-06-12
  • JVM调优方法的示例分析
    这篇文章主要介绍了JVM调优方法的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。JVM调优总结Young(年轻代)年轻代分三个区。一个Eden区,两个Survivor...
    99+
    2023-06-17
  • JVM中GC调优的示例分析
    小编给大家分享一下JVM中GC调优的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!那些GC的默认值其实GC或者说JVM的参数非常非常的多,有控制内存使用的:有控制JIT的:有控制分代比例的,也有控制GC并发的:当然...
    99+
    2023-06-15
  • CSS中优先级的示例分析
    这期内容当中小编将会给大家带来有关CSS中优先级的示例分析,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。计算优先级优先级是根据由每种选择器类型构成的级联字串计算而成的。他...
    99+
    2024-04-02
  • CentOS5.x系统内核优化的示例分析
    这篇文章主要为大家展示了“CentOS5.x系统内核优化的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“CentOS5.x系统内核优化的示例分析”这篇文章吧。主要是针对/etc/sysc...
    99+
    2023-06-10
  • css优先级计算的示例分析
    这篇文章主要为大家展示了“css优先级计算的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“css优先级计算的示例分析”这篇文章吧。主要的css选择器有i...
    99+
    2024-04-02
  • 网页css优先级的示例分析
    这篇文章主要为大家展示了“网页css优先级的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“网页css优先级的示例分析”这篇文章吧。在讲CSS优先级之前,我们得要了解什么是CSS,CSS是...
    99+
    2023-06-08
  • CentOS系统环境精简优化的示例分析
    这篇文章主要介绍CentOS系统环境精简优化的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!第一步、删除不必要的自带软件包yum remove Deployment_Guide-en-US finger cu...
    99+
    2023-06-10
  • MySQL中SQL优化建议的示例分析
    这期内容当中小编将会给大家带来有关MySQL中SQL优化建议的示例分析,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。今天早上看到同事的一个优化需求,优化的时间其实不多,但...
    99+
    2024-04-02
  • MySQL中SQL语句优化的示例分析
    这篇文章主要介绍MySQL中SQL语句优化的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!sql如下:sql强制用了into_time索引# Time: 2017-02-14...
    99+
    2024-04-02
  • Linux系统用户管理之/etc/group组文件的示例分析
    这篇文章将为大家详细讲解有关Linux系统用户管理之/etc/group组文件的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。具有某种共同特征的用户集合起来就是用户组(Group)。用户组(Gro...
    99+
    2023-06-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作