前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MySQL in 太慢的 3 种优化方案

MySQL in 太慢的 3 种优化方案

作者头像
阿珍
发布2024-05-30 11:39:22
3840
发布2024-05-30 11:39:22

MySQL in 太多出现慢的原因

在MySQL中有一个配置参数eq_range_index_dive_limit,它的作用是一个等值查询(比如:in 查询),其等值条件数小于该配置参数,则查询成本分析使用扫描索引树的方式分析,如果大于等于该配置参数,则使用索引统计的方式分析。使用扫描索引树的方式分析在MySQL内部叫做index dives,使用索引统计的方式分析在MySQL内部叫做index statistics

eq_range_index_dive_limit 默认值是 200 .

代码语言:javascript
复制
csharp复制代码select * from dogs where id in (1, 2, 3, 4);

结合上面这条 SQL,就是如果 SQL 中 IN 查询字段 id 的值出现的数量小于 eq_range_index_dive_limit,则走索引树扫描分析查询成本,大于等于 eq_range_index_dive_limit,则走索引统计的方式分析查询成本。

扫描索引树的方式分析 SQL 的查询成本,它的好处就是在 IN 查询的值数量不多时,得到的成本结果是精确的,这就意味着 MySQL 可以选择正确的执行计划,保证语句查询的性能。你现在一定有个疑问:为什么说是在 IN 查询的值数量不多时才是精确的,因为扫描性能的原因,MySQL 在 IN 查询的值数量很多的情况下,扫描索引树成本提高,性能下降,导致查询成本分析代价也随之提高了。

索引统计的方式分析 SQL 的查询成本,由于无需扫描索引树,所以,它的优势就是查询成本分析过程快,代价低。但是,它的缺点也很明显,由于无需扫描索引树,通过粗略统计索引使用情况,得出查询成本,导致 MySQL 可能选错执行计划,使得 SQL 查询性能下降。

解决方案

方案一

可以通过拆分 in 的数量, 分批查询.
代码语言:javascript
复制
csharp复制代码select * from dogs where id in (1, 2);
代码语言:javascript
复制
csharp复制代码select * from dogs where id in (3, 4);

这种方法缺点也明显, 对于分页或者是查询总条件的一部分并不能实现.

方案二

使用 union all 实现内存级别临时表.
代码语言:javascript
复制
sql复制代码select *
from users where task_created > '2020-01-01' and  task_tag_id in ('-1', '1' , ....'1000个');

结果: 在 1 s 631 ms (execution: 172 ms, fetching: 1 s 459 ms) 内检索到从 1 开始的 500 行

代码语言:javascript
复制
sql复制代码select * from users u
    inner join (select -99 as id union all select '1' union all select '-1'
union all select '1' ) as temp on u.task_tag_id = temp.id
where task_created > '2020-01-01'

结果: 在 383 ms (execution: 201 ms, fetching: 182 ms) 内检索到从 1 开始的 500 行

方案三

使用 实体表

创建实体表

代码语言:javascript
复制
sql复制代码create table jump_data
(
    id          bigint auto_increment
        primary key,
    user_id      bigint   default -1                not null comment '人员id',
    hash        varchar(70)          not null comment '当前存储关联 hash 值',
    ref         varchar(100)                comment '关联数据 id',
    ref_long    bigint                             null,
    create_time datetime default CURRENT_TIMESTAMP null comment '创建时间',
    index idx_hash_ref(hash, ref),
    index idx_hash_ref_long(hash, ref)
);
  1. 将上面 task_tag_id 插入至 临时表
    1. 可使用 insert values 插入
  2. 如果是结果值可以直接使用
    1. insert select 插入

使用

代码语言:javascript
复制
csharp复制代码select *
from users u  inner join jump_data jd on u.hash = '' and u.ref_long = u.id
where task_created > '2020-01-01'

⚠ 注意点

  1. 需要及时清理 jump_data 表
  2. 定时需要 truncate 表因为反复的新增和删除导致 MySQL 预估数据不准确导致速度下降

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • MySQL in 太多出现慢的原因
  • 解决方案
    • 方案一
      • 可以通过拆分 in 的数量, 分批查询.
    • 方案二
      • 使用 union all 实现内存级别临时表.
    • 方案三
      • 使用 实体表
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档