06_ MySQL优化实战

news2024/11/27 5:26:36

1. 计算并指定索引长度

阿里开发手册:

强制】在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度。
说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分度会高达 90%以上,可以使用 count(distinct left(列名,索引长度)) / count(*) 的区分度来确定。

测试:

-- address长度为10,当截取到5的时候查询区分度高达0.9572(dept表是随机数据 根据自己的情况判断)
SELECT COUNT(DISTINCT LEFT(address,5)) / COUNT(*) FROM dept;
-- 创建address列的索引并指定长度为5(address可以为空 varchar类型,字节数为:5*3+3 = 18)
ALTER TABLE dept ADD INDEX idx_address(address(5));
-- 可以看到address使用的索引长度为18
EXPLAIN SELECT * FROM dept WHERE address IS NULL;

2. 实现并优化8个SQL

#删除两个表的所有索引
#1、列出自己的掌门比自己年龄小的人员
EXPLAIN SELECT * FROM t_emp c 
	INNER JOIN (SELECT a.id, a.deptName, b.age FROM t_dept a INNER JOIN t_emp b ON a.CEO=b.id) v ON c.deptId=v.id
WHERE c.age > v.age;

EXPLAIN SELECT SQL_NO_CACHE * FROM dept a 
	INNER JOIN t_emp b ON a.CEO=b.id 
	INNER JOIN t_emp c ON c.deptId=a.id
WHERE c.age > b.age;

create index idx_deptId on t_emp(deptId);

#2、列出所有年龄低于自己门派平均年龄的人员
EXPLAIN select SQL_NO_CACHE * from emp c 
	LEFT JOIN (select b.deptId,AVG(b.age) avgage  from emp b GROUP BY b.deptId
	) v on c.deptId=v.deptId
where c.age < v.avgage;

EXPLAIN select * from (select b.deptId, AVG(b.age) avgage from emp b GROUP BY b.deptId) v 
	LEFT JOIN emp c on c.deptId=v.deptId
where c.age < v.avgage;

CREATE INDEX idx_deptId on emp(deptId);


#3、列出至少有2个年龄大于40岁的成员的门派

explain select SQL_NO_CACHE a.deptId, b.deptName, count(*) cou 
from t_emp a 
	INNER JOIN t_dept b on a.deptId=b.id 
where a.age>40 
GROUP BY a.deptId 
HAVING cou >= 2;
# 使用数据量少的表的字段分组
explain select SQL_NO_CACHE b.id, b.deptName, count(*) cou 
from t_dept b 
	STRAIGHT_JOIN t_emp a on a.deptId=b.id 
where a.age>40 
GROUP BY b.id
HAVING cou >= 2;

create INDEX idx_dept on t_emp(deptId, age);

#4、至少有2位非掌门人成员的门派

EXPLAIN select SQL_NO_CACHE a.deptId,b.deptName,count(*) cou
from t_emp a 
	INNER JOIN t_dept b on a.deptId=b.id 
where a.id!=b.CEO 
GROUP BY a.deptId
HAVING cou >= 2;

explain select a.deptId,c.deptName,count(*) cou from t_emp a LEFT JOIN t_dept b on a.id=b.ceo INNER JOIN t_dept c on a.deptId=c.id 
where b.ceo is null
GROUP BY a.deptId
HAVING cou>=2

CREATE INDEX idx_deptId on t_emp(deptId);
CREATE INDEX idx_ceo on t_dept(ceo);

#5、列出全部人员,并增加一列备注“是否为掌门”,如果是掌门人显示是,不是掌门人显示否
select a.id, a.`name`, CASE WHEN b.CEO IS NULL THEN '是' ELSE '否' END '是否掌门人' 
from t_emp a LEFT JOIN t_dept b on a.id=b.CEO;

#6、列出全部门派,并增加一列备注“老鸟or菜鸟”,若门派的平均值年龄>50显示“老鸟”,否则显示“菜鸟”
select a.id,a.deptName,AVG(b.age),IF(AVG(b.age)>50, '老鸟', '菜鸟') '老鸟or菜鸟' 
from t_dept a INNER JOIN t_emp b on a.id=b.deptId GROUP BY a.id;


#7、显示每个门派年龄最大的人


CREATE INDEX idx_deptId on t_emp(deptId);
CREATE INDEX idx_age on t_emp(age);

#8、显示每个门派年龄第二大的人·
SET @last_deptid=0;
SELECT a.id,a.deptid,a.name,a.age,a.rk
 FROM(    
    SELECT t.*,
     IF(@last_deptid=deptid,@rank:=@rank+1,@rank:=1) AS rk,
     @last_deptid:=deptid AS last_deptid
    FROM t_emp t
    ORDER BY deptid,age DESC
 )a WHERE a.rk=2;

UPDATE t_emp SET age=100 WHERE id = 2

SET @rank=0;
SET @last_deptid=0;
SET @last_age=0;
SELECT t.*,
	IF(@last_deptid=deptid, IF(@last_age = age, @rank, @rank:=@rank+1),@rank:=1) AS rk, 
	@last_deptid:=deptid AS last_deptid,
	@last_age :=age AS last_age
FROM t_emp t
ORDER BY deptid,age DESC

CALL proc_drop_index('mydb', 't_emp');
CALL proc_drop_index('mydb', 't_dept');
CALL proc_drop_index('mydb', 'emp');
CALL proc_drop_index('mydb', 'dept');

3. 时间日期处理(了解)

SELECT DATE_FORMAT(NOW() , '%Y年%m月%d日 %H时%i分%s秒');
SELECT NOW();
SELECT * FROM ucenter_member WHERE DATE(gmt_create) = '2019-01-02';
SELECT * FROM ucenter_member WHERE DATE_FORMAT(gmt_create , '%Y-%m-%d') = '2019-01-02';

4. 行转列

测试表:

CREATE TABLE t_score(
    id INT(11) NOT NULL auto_increment,
    stuid VARCHAR(20) NOT NULL COMMENT 'id',
    subject VARCHAR(20) COMMENT '科目',
    score DOUBLE COMMENT '成绩',
    PRIMARY KEY(id)
)

测试数据:

INSERT INTO t_score(stuid,subject,score) VALUES ('001','Java基础',90);
INSERT INTO t_score(stuid,subject,score) VALUES ('001','mysql',92);
INSERT INTO t_score(stuid,subject,score) VALUES ('001','Javaweb',80);
INSERT INTO t_score(stuid,subject,score) VALUES ('002','Java基础',88);
INSERT INTO t_score(stuid,subject,score) VALUES ('002','mysql',90);
INSERT INTO t_score(stuid,subject,score) VALUES ('002','Javaweb',75.5);
INSERT INTO t_score(stuid,subject,score) VALUES ('002','ssm',100);
INSERT INTO t_score(stuid,subject,score) VALUES ('003','Java基础',70);
INSERT INTO t_score(stuid,subject,score) VALUES ('003','mysql',85);
INSERT INTO t_score(stuid,subject,score) VALUES ('003','Javaweb',90);
INSERT INTO t_score(stuid,subject,score) VALUES ('003','ssm',82);
SELECT * FROM t_score;

 

需求:行转列显示学生直观显示学生各科成绩

SELECT stuid ,
SUM(IF(SUBJECT = 'Java基础' , score , NULL)) 'Java基础',
SUM(IF(SUBJECT = 'mysql' , score , NULL)) 'mysql',
SUM(IF(SUBJECT = 'Javaweb' , score , NULL)) 'Javaweb',
SUM(IF(SUBJECT = 'ssm' , score , NULL)) 'ssm'
FROM t_score
GROUP BY stuid;

 

5. 删除重复行

插入重复数据:

INSERT INTO t_score(stuid,SUBJECT,score) VALUES ('001','Java基础',5);
INSERT INTO t_score(stuid,SUBJECT,score) VALUES ('001','mysql',90);
INSERT INTO t_score(stuid,SUBJECT,score) VALUES ('001','Javaweb',1);
INSERT INTO t_score(stuid,SUBJECT,score) VALUES ('002','Java基础',22);
INSERT INTO t_score(stuid,SUBJECT,score) VALUES ('002','mysql',55);
INSERT INTO t_score(stuid,SUBJECT,score) VALUES ('002','Javaweb',1.5);
INSERT INTO t_score(stuid,SUBJECT,score) VALUES ('002','ssm',2);
SELECT * FROM t_score ORDER BY stuid,SUBJECT;

 

需求:每个学生同一学科有多个成绩的,保留分数高的

DELETE FROM t_score WHERE id NOT IN(
	SELECT tmp.id FROM
		(SELECT id FROM t_score t1 JOIN (
			SELECT stuid , SUBJECT , MAX(score) m_score 
			FROM t_score 
			GROUP BY stuid , SUBJECT) t2
		ON t1.`stuid` = t2.stuid 
		AND t1.`subject` = t2.subject 
		AND t1.`score` = t2.m_score)tmp
);
SET @stuid:=0;
SET @subject:='';
SET @rank:= 1;
DELETE FROM t_score WHERE id IN(
SELECT id
FROM(
SELECT * , IF(@stuid = stuid , IF(@subject = SUBJECT  , @rank:=@rank+1 ,@rank:=1) , @rank:=1) 'rank',
	@stuid:=stuid , @subject:=SUBJECT
FROM t_score
ORDER BY stuid , SUBJECT ,score DESC) tmp
WHERE tmp.rank !=1);

6. 窗口函数

窗口函数和普通聚合函数很容易混淆,二者区别如下:

Ø 聚合函数是将多条记录聚合为一条

Ø 窗口函数是每条记录都会执行,有几条记录执行完还是几条

按照功能划分,可以把MySQL支持的窗口函数分为如下几类:

# 序号函数:没有参数
row_number()/rank()/dense_rank()
# 分布函数:没有参数
percent_rank():所在行数/总行数的百分比
cume_dist():累积分布值
# 前后函数:参数有3个(expr:列名;n:偏移量;default_value:超出记录窗口的默认值)
lag(): 从当前行开始往前获取第N行,缺失则使用默认值
lead():从当前行开始往后获取第N行,缺失则使用默认值
# 头尾函数: 参数1个(expr:列名)
first_value():返回分组内截止当前行的第一个值
last_value():返回分组内截止当前行的最后一个值
# 其他函数: 
-- 参数有2个(expr:列名;n:偏移量)
nth_value():返回分组内截止当前行的第N行
-- 参数有1个(expr:列名;)
ntile():返回当前行在分组内的分桶号
/*
  语法结构:
    window_function ( expr ) OVER (
    PARTITION BY ...
    ORDER BY ...
    )

其中,window_function 是窗口函数的名称;
expr 是参数,有些函数不需要参数;OVER子句包含三个选项:
1、分区(PARTITION BY)
PARTITION BY选项用于将数据行拆分成多个分区(组),它的作用类似于GROUP BY分组。如果省略了 PARTITION BY,所有的数据作为一个组进行计算
2、排序(ORDER BY)
OVER 子句中的ORDER BY选项用于指定分区内的排序方式,与 ORDER BY 子句的作用类似

OVER后面括号中的内容可以抽取:
 	WINDOW w AS ( 
 		PARTITION BY ...
    	ORDER BY ...
    )
*/

测试窗口函数的使用:

-- 1、查询员工信息和他部门年龄升序排列前一名员工的年龄
SELECT * , lead(age , 1,-1) over(
		PARTITION BY deptId
	) last_emp_age 
FROM t_emp;

-- 2、查询每个员工在自己部门由大到小的年龄排名
select * ,
	row_number() over(PARTITION BY deptid ORDER BY age DESC) as row_num,
from t_emp;
# 或者
SELECT * ,
	row_number() over w AS row_num # w代表使用的
FROM t_emp
WINDOW w AS(PARTITION BY deptid ORDER BY age DESC);

接下来,我们来实现这么一个需求:查询员工表中每个部门的的年龄前两名

-- 查询每个员工所在部门的其他员工 如果年龄大于等于自己的小于等于两个,则保留自己的数据
SELECT * FROM t_emp t1
WHERE (SELECT COUNT(1) FROM t_emp t2 WHERE t2.`deptId`=t1.`deptId` AND t2.age>=t1.`age`)<=2
ORDER BY t1.`deptId` DESC, t1.age DESC;

上面的SQL是不是不好理解,接下来我们采用窗口函数看看如何优雅的实现同样的功能

select * from(
  select row_number() over(partition by deptid order by age desc) as row_num,
  id,name,sal,deptid
  from t_emp
) t where row_num <= 2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/627179.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2.4 网络设计与redis、memcached、nginx组件

目录 一、网络模块需要处理哪些事情二、reactor网络设计模型三、网络模块与业务的关系四、redis、memcached、nginx1、redis2、memcached3、ngnix4、总结 一、网络模块需要处理哪些事情 网络编程主要关注客户端与服务端交互的四个问题&#xff1a; 1、连接建立 2、消息到达 3、…

学历不代表能力,但学历不够就意味着没资格!

今年的高考报名人数再创历史新高。 据悉&#xff0c;2023年全国高考报名人数1291万人&#xff0c;比去年增加98万人。 那么&#xff0c;今年的高校毕业生人数呢&#xff1f; 据人社部统计,今年我国高校毕业生人数达到1158万&#xff0c;继2022年破千万后再创历史新高。 大家…

Vue路由到新的页面,页面的名称需要改变

如下图&#xff1a;在页面中点击“属性列表”和“参数列表”的时候&#xff0c;要路由到新的页面&#xff0c;之后页面的title不用路由中的名称&#xff0c;而是用新的名称。也就是要显示对应的按钮名称&#xff0c;这个路由地址的名称是动态的。 在旧的页面上加上&#xff1a;…

汇报演示领导都说好,只因用了Smartbi幻灯片这个功能

在日常工作中&#xff0c;定期以PPT的方式汇报工作是非常常见的需求。假设你是一位销售经理&#xff0c;每个月都要参加公司的销售会议。在会议上&#xff0c;你需要向团队和高层展示销售数据、市场趋势和业绩报告等信息。过去&#xff0c;你通常是PPT来制作演示文稿&#xff0…

链表及相关面试题

链表 单链表 特点&#xff1a; 逻辑上顺序存储&#xff0c;物理上无序存储头指针根据情况而定&#xff0c;不保存数据&#xff0c;很多操作需要头指针&#xff0c;比如原地反转链表。每个节点包含 data, Node next保存下个Node public class LinkList {public Node headern…

系统初始化加载动画逻辑以及隐藏

需求&#xff1a;进入系统默认有如下的加载界面&#xff0c;但是由于网页内嵌到了其他网页中&#xff0c;这种环境下进入时再加载就不合适&#xff0c;需要隐藏掉。 因此本文的内容逻辑为 文章目录 研究加载逻辑解决需求&#xff1a;在被内嵌时隐藏掉loading 研究加载逻辑 1.…

【SpinalHDL快速入门】3、Scala 快速入门

SpinalHDL本质上来讲是Scala语言的一个库&#xff0c;所以需要先学习Scala&#xff0c;才能在此基础上学习SpinalHDL。 文章目录 Scala 基础Scala 数据类型&#xff08;5种&#xff1a;Boolean、Int、Float、Double、String&#xff09;Scala VariablesScala FunctionsReturnRe…

Python自动化测试框架:unittest介绍

Unittest是Python中最常用的测试框架之一&#xff0c;它提供了丰富和强大的测试工具和方法&#xff0c;可以帮助开发者更好地保证代码质量和稳定性&#xff0c;本文就来介绍下Unittest单元测试框架。 1. 介绍 unittest是Python的单元测试框架&#xff0c;它提供了一套丰富的测…

2023软件测试卷出天际!!!性能测试为啥一枝独秀?

近十年是中国互联网发展最快的10年&#xff0c;互联网用户从4亿增长至10亿。面对用户量的暴增&#xff0c;用户体验就成为互联网产品最大的考验。而 影响用户体验的最重要因素就是性能。 流量为王的时代&#xff0c;性能测试是所有产品上线前必须通过的重要环节。 企业招聘性…

12米与30米TanDEM-X数字高程模型DEM数据的下载申请方法

本文介绍全球12米与30米高空间分辨率的数字高程模型&#xff08;DEM&#xff09;数据——TanDEM-X数据的下载申请方法。 Tandem-X卫星项目于2010年6月启动&#xff0c;并于2010年6月21日和2010年12月21日分别发射两颗卫星&#xff0c;即TerraSAR-X和TanDEM-X。Tandem-X卫星之间…

裸辞3个月,面试了25家公司,这难度真不一般····

上半年裁员&#xff0c;下半年裸辞&#xff0c;有不少人高呼裸辞后躺平真的好快乐&#xff01;但也有很多人&#xff0c;裸辞后的生活五味杂陈。 面试25次终于找到心仪工作 因为工作压力大、领导PUA等各种原因&#xff0c;今年2月下旬我从一家互联网小厂裸辞&#xff0c;没想到…

【Android】WMS(五)输入事件原理

输入事件原理 安卓输入事件整体流程 Android 系统是由事件驱动的&#xff0c;而 input 是最常见的事件之一&#xff0c;用户的点击、滑动、长按等操作&#xff0c;都属于 input 事件驱动&#xff0c;其中的核心就是 InputReader 和 InputDispatcher。 InputReader 和 InputD…

申请国家标准项目管理专业人员能力评级(CSPM)报名条件有哪些?

2021年10月&#xff0c;中共中央、国务院发布的《国家标准化发展纲要》明确提出构建多层次从业人员培养培训体系&#xff0c;开展专业人才培养培训和国家质量基础设施综合教育。建立健全人才的职业能力评价和激励机制。由中国标准化协会&#xff08;CAS&#xff09;组织开展的项…

3.JavaScript常用对象数组对象

3.1、数组对象 3.1.1、概述 目录 3.1、数组对象 3.1.1、概述 3.1.2、创建数组 3.1.2.1、使用对象创建 3.1.2.2、使用字面量创建 3.1.3、遍历数组 3.1.4、数组属性 3.1.5、数组方法 3.2、函数对象 3.2.1、call()和apply() 3.2.2、this指向 3.2.3、arguments参数 3…

JavaSE-06 [面向对象+封装]

JavaSE-06 [面向对象封装] 第一章 面向对象思想 1.1 面向过程和面向对象 面向过程&#xff1a; 面向过程就是分析出解决问题所需要的步骤&#xff0c;然后用函数把这些步骤一步一步实现&#xff0c;使用的时候一个一个依次调用就可以了面向对象&#xff1a; 面向对象是把构成…

PYTHON元素定位方式总结

一&#xff0c;常用的8种定位方式 id定位 driver.find_element_by_id("id 值")   driver.find_element(by "id", value "ID值" ) name定位 单个元素&#xff1a;     driver.find_element_by_name("name值")     drive…

总结:记一次docker调试镜像的问题

一、背景 同事让帮忙部署一个应用到QKE&#xff0c;给了我镜像地址与配置文件。 由于要将配置文件映射到容器中&#xff0c;我创建了configmap&#xff0c;然后应用中将configmap中key对应的内容映射到了容器中的配置文件中。 但是我遇到了一个问题&#xff1a; 容器频繁快…

100多的ipad触控笔好用吗?ipad可以用的手写笔推荐

随着IPAD的普及&#xff0c;一些学习党已经从传统的纸质教学走向了无纸化教学。所以&#xff0c;本来就是苹果品牌专利的电容笔&#xff0c;现在更是成为了炙手可热的产品&#xff0c;很多人都对这款售价近千元的电容笔充满了好奇。我认为&#xff0c;对于职业画师来说&#xf…

你“心累”吗?教你方法

解决“心累”的方法来了 前言一、“心累”的原因二、认识“心累”三、走出“心累”四、发现自己的“优势” 前言 不管是脑力劳动还是体力劳动&#xff0c;工作生活本身并没有多么累&#xff0c;但总感觉累。这就是我今天想说的话题&#xff1a;心累。 如果你也被这个状态折磨&a…

用好 mysql 分区表

为了保证mysql的性能&#xff0c;我们都建议mysql单表不要太大&#xff0c;也经常有人问我这样的问题&#xff0c;整体来说呢&#xff0c;建议是&#xff1a;单表小于2G&#xff0c;记录数小于1千万&#xff0c;十库百表。如果但行记录数非常小&#xff0c;那么记录数可以再偏大…