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 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> sql优化案例分析(3) -> 正文阅读

[大数据]sql优化案例分析(3)

目录

1、使用索引提示来优化sql

1.1?索引提示原理

1.2?问题描述

1.3?优化方案

1.3.1?重写sql

1.3.2?使用索引提示

?1.4?总结

2?使用union all 替换 union实现sql优化

2.1?问题背景

2.2?解决方案

方案1 :用in来实现范围查询

方案2 :用or条件来实现多值匹配

方案3:使用union对结果集进行求并集,需要去重

方案4:使用union all对结果集进行求并集,不需要去重



1、使用索引提示来优化sql

参考文档:force index mysql_mysql force index 优化案例

1.1?索引提示原理

?

?

1.2?问题描述

有两张表,员工表:employees,员工工资表:salaries

员工表:employees,数据大概300024条(30万),定义如下:

CREATE TABLE `employees` (
  `emp_no` int(11) NOT NULL,
  `birth_date` date NOT NULL,
  `first_name` varchar(14) NOT NULL,
  `last_name` varchar(16) NOT NULL,
  `gender` enum('M','F') NOT NULL,
  `hire_date` date NOT NULL,
  PRIMARY KEY (`emp_no`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

?员工表:salaries,数据条数为2844047(284万)条,定义如下:

CREATE TABLE `salaries` (
  `emp_no` int(11) NOT NULL,
  `salary` int(11) NOT NULL,
  `from_date` date NOT NULL,
  `to_date` date NOT NULL,
  PRIMARY KEY (`emp_no`,`from_date`),
  CONSTRAINT `salaries_ibfk_1` FOREIGN KEY (`emp_no`) REFERENCES `employees` (`emp_no`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- 根据员工工号升序排序取出前10条数据,返回员工工号、薪资
select e.emp_no,s.salary from employees e ,salaries s where e.emp_no=s.emp_no order by s.emp_no asc limit 0,10;

语义分析:从employees表中根据主键empno排序取前10条数据,然后与salaries做联表查询,返回工号与薪资,这不应该慢的,全部走了索引,但是执行效果与执行计划如下:

执行效果如下:耗时大概3s

执行计划如下:

?分析以上执行计划,感觉非常不合理,为什么要对员工表e进行全表扫描,然后扫描大概299025,数据量太大,就得依赖临时表、文件排序,所以Extra中含有:Using index; Using temporary; Using filesort,这非常不合理,肯定有问题,明明只是取10条数据,不应该进行索引
扫描。

1.3?优化方案

1.3.1?重写sql

? ? sql中只是将排序字段从s.emp_no asc修改成了e.emp_no asc,然后执行效果与执行计划发生了
巨大的变化。

-- 方案1 重写sql
select e.emp_no,s.salary from employees e ,salaries s where e.emp_no=s.emp_no order by e.emp_no asc limit 0,10;

以下是执行效果:(执行时间耗时0.218s)

以下是执行计划:

?执行计划中,扫描聚族索引10条数据,并且没有了临时表,没有了文件排序,性能自然就提升上来了。

1.3.2?使用索引提示

本文主要讲解方案2 ,使用索引提示来解决这个问题。?这个sql仅仅是加了force index(PRIMARY)?告诉查询分析器要走主键索引。


-- 方案2 索引提示
select e.emp_no,s.salary from employees e force index(PRIMARY),salaries s where e.emp_no=s.emp_no order by s.emp_no asc limit 0,10;

执行效果如下:大概0.2s

执行计划如下,与方案1基本相同:

?1.4?总结

? 通过使用force index?可显示提示查询优化器选择用户指定的索引,从而达到优化sql的目的。

2?使用union all 替换 union实现sql优化

2.1?问题背景

员工表:employees,数据大概300024条(30万),定义如下:????????

CREATE TABLE `employees` (
  `emp_no` int(11) NOT NULL,
  `birth_date` date NOT NULL,
  `first_name` varchar(14) NOT NULL,
  `last_name` varchar(16) NOT NULL,
  `gender` enum('M','F') NOT NULL,
  `hire_date` date NOT NULL,
  PRIMARY KEY (`emp_no`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

?现有以下需求:需要查询工号emp_no=10001或者10010的员工信息,该需求可以用以下4种sql来实现,emp_no是主键,不重复。这实际上是一个典型的多值匹配问题。

2.2?解决方案

方案1 :用in来实现范围查询

select e1.* from employees e1  where e1.emp_no in (10001,10010);

?可以看出使用in条件,会使用主键索引,访问方式为range索引范围查询,并且使用where条件来实现数据筛选。

方案2 :用or条件来实现多值匹配

select e1.* from employees e1  where e1.emp_no =10001 or e1.emp_no = 10010;

?与方案1结果完全相同。

方案3:使用union对结果集进行求并集,需要去重


   select e1.* from employees e1  where e1.emp_no = 10001
union  
  select e2.* from employees e2  where e2.emp_no = 10010
	
	

?但是我们从执行计划中观察到,有3条执行计划,这是因为union是默认要对两个结果集进行去重的,其工作原理是先把结果集1中的数据记录插入到一张临时表中,然后,遍历结果集2中的数据记录,判断两条记录中的所有的字段值都相等,则判定为重复,则忽略;如果不重复,则插入到临时表中。所以union all有一个不好的地方,就是要用临时表来实现去重,而这个过程是非常消耗性能的。所以我们明知两个结果集不可能重复,所以我们就一定不要使用union。

方案4:使用union all对结果集进行求并集,不需要去重


   select e1.* from employees e1  where e1.emp_no = 10001
union  all
  select e2.* from employees e2  where e2.emp_no = 10010
	

?

?与方案1、方案2、方案3相比,这个执行计划是优的,并且执行时间也是最短的。
所以我们一定要清楚union all?与 union?的区别,正确的选择union 、union all是每个
开发人员应该具备的素养。

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-04-04 12:18:09  更:2022-04-04 12:19:19 
 
开发: 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/24 4:36:19-

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