1,复杂SQL语句类型
1,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;
1.2 相关子查询
相关子查询和普通子查询(也叫非相关子查询)的差别就在于这子查询中是否有对外部查询中涉及到的表的引用。
此时,先执行外部查询,拿到一个结果后,去执行内部查询,判断是否满足条件。
举例: 查询 “工资大于该员工所在部门平均工资的员工”
SELECT employee_number, name FROM employees emp WHERE salary > ( SELECT AVG(salary) FROM employees WHERE department = emp.department # 子查询中的表就是外部查询的引用表 );
1.3 行转列 或者 列转行
行转列: 行的某列数据,转化到多个列上。
方法:主要是使用CASE WHEN 条件函数,增加表格的列。
比如:
学生表student: id name subject score sam yuwen 50 sam shuxue 70 bob yuwen 78 ##### SELECT id, name AS 姓名 , sum(CASE Subject WHEN 'yuwen' THEN score ELSE 0 END) AS 语文 , sum(CASE Subject WHEN 'shuxue' THEN score ELSE 0 END) AS 数学 , sum(CASE Subject WHEN 'yingyu' THEN score ELSE 0 END) AS 英语 FROM student
列转行: 某列的数据,转化到多个行上。
方法:假设在HIVE 库内,使用LATERAL VIEW语法
电影信息表 movie_info: name types 《疑犯》 悬疑,动作,科幻,爱情 --> name type 《疑犯》 悬疑 《疑犯》 动作 《疑犯》 科幻 《疑犯》 爱情 SELECT name, type FROM movie_info LATERAL VIEW explode(types) alias_table AS type;
1.4 窗口函数 (针对HIVE)
语法:
题目: 要求拉出一个表,包含当前表信息,并且包含该次消费的上一次消费日期。
# 订单表order:(name ,date, cost)
name: 顾客姓名 date: 日期 cost: 花费
select name, date, cost, lag(cost, 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, wm_concat(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; # 语句适用于HIVE SQL。 ??
2,Explain 语句
对于hive:
explain会把查询语句转化成stage组成的序列,主要由三方面组成:
1:查询的抽象语法树
2:plane中各个stage的依赖情况
3:每个阶段的具体描述:描述具体来说就是显示出对应的操作算子和与之操作的对应的数据,例如查询算子,filter算子,fetch算子等等。
这里,你可以查看是否有严重计算密集的stage(或者是其中的算子,比如map , reduce , fillter , fetch , group by等等) , 可以查看每个算子操作的数据大小情况。使你可以看到
HSQL执行的mapreduce 底层运行情况。 由此决定如何调优(参见我的另一篇文章: HIVE 调优思路和实践)。优化思路的前提是你必须对Mapreduce的原理比较熟悉。
对于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(从左到右,性能越来越差)
rows: rows 列显示MySQL认为它执行查询时必须检查的行数。
fillter: 表示此查询条件所过滤的数据的百分比 , 数值越高越好。
根据expain语句提供的信息,查看SQL 执行计划,确定延迟最大的查询阶段,并对此进行优化。
措施包括:
1,修改查询SQL逻辑,最大程度利用索引结构,加速查询效率。
2,修改表的索引设置 。
3,MySQL资源优化配置层面进行优化。