IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> mysql in 子查询无法使用索引全表扫描 慎用in -> 正文阅读

[大数据]mysql in 子查询无法使用索引全表扫描 慎用in

背景

最近慢sql 性能优化 发现一个调用频率高的sql 使用 in 子查询,导致外层全表扫描的问题?
为什么会产生这样的问题?特别强调在优化的使用发现 使用in 和优化后的效果差距 300倍,可见全表扫描的效果可多厉害。 mysql 版本 5.6

参考

搜集了一下资料发现 https://www.cnblogs.com/wy123/archive/2017/06/28/7092194.html 这篇 文章特别像我们的场景,子查询中 查询一个条件,然后非常慢使用不上索引

实践

创建表

create table test_table2
(
	id int auto_increment
		primary key,
	pay_id int null,
	pay_time datetime null,
	other_col varchar(100) null
);

create index test_table2_pay_id_index
	on test_table2 (pay_id);

执行计划

explain extended select * from test_table2
where  pay_id in(
    select pay_id from test_table2
    where pay_id  > 800
     group by pay_id
     having count(pay_id) > 2
 );

从执行计划可以看出 先执行子查询(SUBQUERY), 然后扫描了全表的数据。

[
  {
    "id": 1,
    "select_type": "PRIMARY",
    "table": "test_table2",
    "partitions": null,
    "type": "ALL",
    "possible_keys": null,
    "key": null,
    "key_len": null,
    "ref": null,
    "rows": 1010,
    "filtered": 100,
    "Extra": "Using where"
  },
  {
    "id": 2,
    "select_type": "SUBQUERY",
    "table": "test_table2",
    "partitions": null,
    "type": "range",
    "possible_keys": "test_table2_pay_id_index",
    "key": "test_table2_pay_id_index",
    "key_len": "5",
    "ref": null,
    "rows": 200,
    "filtered": 100,
    "Extra": "Using where; Using index"
  }
]

即使强制指定索引也没有用

explain extended select * from test_table2 force index(test_table2_pay_id_index)
where  pay_id in(
    select pay_id from test_table2
    where pay_id  > 800
     group by pay_id
     having count(pay_id) > 2
    );

为什么?

如果直接使用这种查询 (pay_id) in 常量

效率杠杠的,使用了索引 pay_id

explain  select * from test_table2 where pay_id in(800,900)

为什么没有命中索引?

子查询的结果是未知的,不能作为外层的索引判断 。【高版本mysql优化器应该会优化成连接查询】
以上就是利用,在SQL 查询语言执行流程中,优化器执行计划生成已经索引选择阶段,子查询的结果无法提供任何的判断依据,因此不能作为外层判断索引的依据,由此导致外层直接全表扫描了。具体可以参考一下 Mysql的查询流程。
MySql查询语句执行流程

如何改进

接改为连接查询非常快

explain extended 
select * from test_table2 as t1
  inner join (
    select pay_id from test_table2
    where pay_id  > 800
     group by pay_id
     having count(pay_id) > 2
    )as tmp on tmp.pay_id =t1.pay_id;

总结

对于子查询慎用 in,常量情况下可以使用 in 涉及多表操作 in 最好使用 连接查询,性能差异可能几百倍。

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-03-22 20:40:57  更:2022-03-22 20:42:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/28 0:00:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码