复杂SQL语句及其优化
一,复杂SQL语句类型
1 ,笛卡尔连接
题目1:找出工资超过各自经理的员工姓名
表:employee(id , name , depid , salary, manager_id )
SELECT e1.name AS employee_name, e1.salary, e2.name AS manager_name, e2.salary
FROM employee e1, employee e2
WHERE e1.manager_id = e2.id
AND e1.salary > e2.salary;
2, 相关子查询
相关子查询和普通子查询(也叫非相关子查询)的差别就在于这子查询中是否有对外部查询中涉及到的表的引用。
此时,先执行外部查询,拿到一个结果后,去执行内部查询,判断是否满足条件。
举例: 查询 “工资大于该员工所在部门平均工资的员工”
SELECT employee_number, name
FROM employees emp
WHERE salary > (
SELECT AVG(salary)
FROM employees
WHERE department = emp.department # 子查询中的表就是外部查询的引用表
);
3, 行转列 或者 列转行
行转列: 行的某列数据,转化到多个列上。
方法:主要是使用CASE WHEN 条件函数,增加表格的列。
比如:
学生表student:
id name subject score
1 sam yuwen 50
1 sam shuxue 70
2 bob yuwen 78
#####
SELECT id, name AS name
, sum(CASE Subject
WHEN 'yuwen' THEN score
ELSE 0
END) AS yuwen_s
, sum(CASE Subject
WHEN 'shuxue' THEN score
ELSE 0
END) AS shuxue_s
, sum(CASE Subject
WHEN 'yingyu' THEN score
ELSE 0
END) AS yingyu_s
FROM student
#######
id name yuwen_s shuxue_s yingyu_s
1 sam 50 0 0
1 sam 0 70 0
2 bob 0 0 78
列转行: 某列的数据,转化到多个行上。
方法1:假设在HIVE 库内,使用LATERAL VIEW语法
电影信息表 movie_info:
name types
《疑犯》 悬疑,动作,科幻,爱情 -->
name type
《疑犯》 悬疑
《疑犯》 动作
《疑犯》 科幻
《疑犯》 爱情 SELECT name, type
FROM movie_info
LATERAL VIEW explode(types) alias_table AS type;
方法2: 在MySQL内,使用 substring_index()函数;
以下例子实现2个功能演示:
1, 实现对 包含分隔符的字符串的分拆,类似split功能。
2, 实现分拆后便签,多行显示功能,也就是行转列。
表event_xihuevent_star 结构内有需要分拆的标签:
event_id commentlabel createtime
1 'a_label,b_label' xxxx
2 'b_label,c_label' xxxx
select a.eventid,
a.createtime,
#a.commentlable,
# substring_index(a.commentlable, ',', b.help_topic_id + 1),
substring_index(substring_index(a.commentlable, ',', b.help_topic_id + 1), ',', -1) single_label // 连接衍生表内有b.help_topic_id列
from event_xihuevent_star a
join mysql.help_topic b
on b.help_topic_id < (length(a.commentlable) - length(replace(a.commentlable, ',', '')) + 1);
# 1, 使用笛卡尔连接
2,在 select 中使用了参数 help_topic_id , 因为where语句在select 之前执行,对movie_info每一行得到一个help_topic_id值。
4, 窗口函数 (针对HIVE)
语法:
题目: 要求拉出一个表,包含当前表信息,并且包含该次消费的上一次消费日期。
# 订单表order:(name ,date, cost)
name: 顾客姓名 date: 日期 cost: 花费
select name, date, cost, lag(date, 1, 0) over(patitioned by name order by date) as preDate from order
二,一些复杂SQL逻辑举例:
1, 每个用户连续签到天数
t_user_attendence表(fdate, fuser_id, fis_sign_in ) 表的说明:日期【fdate】,用户id【fuser_id】,用户当天是否签到【0否1是】
举例;
2020-10-01 002 1
2020-10-02 003 1
2020-10-02 002 0
SELECT fuser_id, datediff('2022-06-26', fdate_max) AS fconsecutive_days # 当前日期 - 最近未签到日期 = 连续签到日期
FROM (
SELECT fuser_id, max(fdate) AS fdate_max #找出用户最近未签到的日期
FROM t_user_attendence
WHERE fis_sign_in = 0
GROUP BY fuser_id
) t1;
2, 每个用户最大的连续签到天数
含义是,在整个签到表的日期范围内,最大的连续签到日期。
表格:同上
表格:同上 SELECT fuser_id, max(length(cut_fsign_record)) AS fmax_days # 对“11111”求长度,就是连续登录天数
FROM (
SELECT fuser_id, fsign_record, cut_fsign_record
FROM (
SELECT fuser_id, concat_ws("",collect_list(fis_sign_in)) AS fsign_record # 多列合并到一行,列值以""号分隔起来
FROM t_user_attendence
GROUP BY fuser_id
) t1
LATERAL VIEW explode(split(fsign_record, '0')) t AS cut_fsign_record # 用0分割列,把列值转多行。(111 111)
) t2
WHERE cut_fsign_record <> ''
GROUP BY fuser_id;
# 语句适用于HSQL
三, Explain 语句
1,HIVE内
explain会把查询语句转化成stage组成的序列,主要由三方面组成:
1:查询的抽象语法树
2:plan中各个stage的依赖情况
3:每个阶段的具体描述:描述具体来说就是显示出对应的操作算子和与之操作的对应的数据,例如查询算子,filter算子,fetch算子等等。
你可以查看是否有严重计算密集的stage(或者是其中的算子,比如map , reduce , fillter , fetch , group by等等) , 可以查看每个算子操作的数据大小情况。使你可以看到
HSQL执行的mapreduce 底层运行情况。 由此决定如何调优(参见我的另一篇文章: HIVE 调优思路和实践)。优化思路的前提是你必须对Mapreduce的原理比较熟悉。
2,MySQL内
explain 语句的输出信息包括: 1, 一个语句被分解成多个查询计划(比如 嵌套查询 ,Union查询)。 2,每个查询计划涉及到数据情况 ,索引使用情况 ,查询效率
Column | JSON Name | Meaning |
---|---|---|
id | select_id | select标识号 |
select_type | None | select类型 |
table | table_name | 这一行数据是关于哪张表的 |
partitions | partitions | 匹配的分区,对于未分区表,该值为空 |
type | access_type | 使用的连接类别,有无使用索引 |
possible_keys | possible_keys | MySQL能使用哪个索引在该表中找到行 |
key | key | MySQL实际决定使用的键(索引) |
key_len | key_length | MySQL决定使用的键长度。如果键是NULL,长度为NULL |
ref | ref | 与索引关联的列 |
rows | rows | mysql认为执行sql时必须被校验的行数 |
filtered | filtered | 表示此查询条件所过滤的数据的百分比 |
Extra | None | 附加信息 |
关注的字段:
type : 常用的类型有:NULL, system, const, eq_ref, ref, range, index, ALL(从左到右,性能越来越差)
- NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成
- system:这个表(也可能是查询出来的临时表)只有一行数据 (= system table). 是const中的一个特例
- const:表最多有一个匹配行,它将在查询开始时被读取。因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。const 表常量次数, const用于查询条件为PRIMARY KEY或UNIQUE索引并与常数值进行比较时的所有部分。
- eq_ref:对于前几个表中的每一行组合,从该表中读取一行。除了system和const,这是最好的连接类型。当连接使用索引的所有部分,并且索引是主键或唯一非空索引时,将使用它。eq_ref可以用于使用= 操作符比较的带索引的列。比较值可以为常量或一个使用在该表前面所读取的表的列的表达式。 这种情况可认为,完全利用索引去查询的类型,效率比较高。
- ref: 对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。如果联接只使用键的最左边的前缀,或如果键不是UNIQUE或PRIMARY KEY(换句话说,如果联接不能基于关键字查询结果为单个行的话),则使用ref。如果使用的键仅仅匹配少量行,该联接类型是不错的。ref可以用于使用=或<=>操作符的带索引的列。
- range: 只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引。key_len包含所使用索引的最长关键元素。在该类型中ref列为NULL。当使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比较关键字列时,可以使用range
- index: 该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。当查询只使用作为单索引一部分的列时,MySQL可以使用该联接类型。
- ALL: 对于每个来自于先前的表的行组合,进行完整的表扫描。如果表是第一个没标记const的表,这通常不好,并且通常在它情况下很差。通常可以增加更多的索引而不要使用ALL,使得行能基于前面的表中的常数值或列值被检索出
rows: rows 列显示MySQL认为它执行查询时必须检查的行数。
fillter: 表示此查询条件所过滤的数据的百分比 , 数值越高越好。
根据expain语句提供的信息,查看SQL 执行计划,确定延迟最大的查询阶段,并对此进行优化。
措施包括:
1,修改查询SQL逻辑,最大程度利用索引结构,加速查询效率。
2,修改表的索引设置 。
3,MySQL资源优化配置层面进行优化。
复杂SQL语句及其优化的更多相关文章
- 谈谈SQL 语句的优化技术
https://blogs.msdn.microsoft.com/apgcdsd/2011/01/10/sql-1/ 一.引言 一个凸现在很多开发者或数据库管理员面前的问题是数据库系统的性能问题.性能 ...
- oracle中sql语句的优化
oracle中sql语句的优化 一.执行顺序及优化细则 1.表名顺序优化 (1) 基础表放下面,当两表进行关联时数据量少的表的表名放右边表或视图: Student_info (30000条数据)D ...
- SQL语句常见优化十大案例
1.慢SQL消耗了70%~90%的数据库CPU资源: 2.SQL语句独立于程序设计逻辑,相对于对程序源代码的优化,对SQL语句的优化在时间成本和风险上的代价都很低:3.SQL语句可以有不同的写法: 1 ...
- Oracle SQL语句性能优化方法大全
Oracle SQL语句性能优化方法大全 下面列举一些工作中常常会碰到的Oracle的SQL语句优化方法: 1.SQL语句尽量用大写的: 因为oracle总是先解析SQL语句,把小写的字母转换成大写的 ...
- sql 语句的优化
sql语句的优化:在大多数情况下,为了更快的遍历表结构,优化器主要是根据定义的索引来提高性能.但是在不合理的SQL语句中,优化器会删去索引进而使用全表扫描, 一般而言,这种sql被称为劣质sql,所以 ...
- Oracle数据库的sql语句性能优化
在应用系统开发初期,由于开发数据库数据比较少,对于查询sql语句,复杂试图的编写等体会不出sql语句各种写法的性能优劣,但是如果将应用系统提交实际应用后,随着数据库中数据的增加,系统的响应速度就成为目 ...
- MySQL索引详解(优缺点,何时需要/不需要创建索引,索引及sql语句的优化)
一.什么是索引? 索引是对数据库表中的一列或多列值进行排序的一种结构,使用索引可以快速访问数据库表中的特定信息. 二.索引的作用? 索引相当于图书上的目录,可以根据目录上的页码快速找到所需的内容,提 ...
- 52 条 SQL 语句性能优化策略,建议收藏
本文会提到 52 条 SQL 语句性能优化策略. 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在where及order by涉及的列上建立索引. 2.应尽量避免在where子句中对字段进行nul ...
- sql语句的优化分析
开门见山,问题所在 sql语句性能达不到你的要求,执行效率让你忍无可忍,一般会时下面几种情况. 网速不给力,不稳定. 服务器内存不够,或者SQL 被分配的内存不够. sql语句设计不合理 没有相应的索 ...
- 如何对于几百行SQL语句进行优化?
1.最近在开发中遇到的一些关于几百行SQL语句做查询的问题,需要如何的解决优化SQL这确实是个问题,对于当下的ORM 框架 EF 以及其他的一些的开源的框架例如Drapper ,以及Sqlite-Su ...
随机推荐
- Docker中apt-get update失败解决方案
一.更换apt的镜像源 1. 进入目录 cd /etc/apt 2. 备份源文件 cp /etc/apt/sources.list /etc/apt/sources.list.bak 3. 更改镜像源 ...
- ES6的Promise用法
一.是什么: promise是异步编程的一种解决方案,它是一个对象,可以获取异步操作的信息,它的出现改善了异步编程,避免了地狱回调,它比传统的解决方案回调函数和事件更合理和更强大 二.promise的 ...
- Centos7系统编译Hadoop3.3.4
1.背景 最近在学习hadoop,此篇文章简单记录一下通过源码来编译hadoop.为什么要重新编译hadoop源码,是因为为了匹配不同操作系统的本地库环境. 2.编译源码 2.1 下载并解压源码 [r ...
- UI自动化中上传与唤醒弹窗
本篇想谈的是在ui自动化中对上传的一些理解,干货满满. 一.是否有必要唤醒弹窗 以selenium为代表的库在进行文件上传时,是可以直接对输入框 "发送" 文件的,其send_ke ...
- SpringBoot多数据源以及事务处理
背景 在高并发的项目中,单数据库已无法承载大数据量的访问,因此需要使用多个数据库进行对数据的读写分离,此外就是在微服化的今天,我们在项目中可能采用各种不同存储,因此也需要连接不同的数据库,居于这样的背 ...
- Vue学习笔记之Vue-Router
1. 概述 Vue Router 是 Vue.js 的官方路由.它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用变得轻而易举.功能包括: 嵌套路由映射 动态路由选择 模块化.基于组件 ...
- 如何在 JavaScript 中使用媒体查询
前言 说起媒体查询想必大家最先想到的都是CSS中@media,没错,这是我们最常用的媒体查询方法,主要用来为我们的网站做适配处理. 比如: h1 { font-size: 2rem; color: g ...
- go常见的坑
1. for循环中使用短变量声明初始值 案例1: type Data struct { d *int } func main() { list := make([]Data, 0) for i := ...
- Ubuntu命令安装默认支持的Qt5版本
1.前置依赖 sudo apt install build-essential sudo apt install cmake 2.只安装默认的Qt模块 # 安装默认SDK # Ubuntu18.04中 ...
- [版本控制-Git]-git学习总结
1.如何将本地的文件添加到已经建好的远程分支上: 1.1 本地文件夹内,右键-git bash - 创建新仓 git init 1.2 git remote add origin 远程仓库的githu ...