当前位置:网站首页>索引+sql练习优化
索引+sql练习优化
2022-06-27 07:35:00 【Fairy要carry】
目录
2.创建存储过程插入数据(利用上面两个函数得到随机编号以及名字)
优势劣势
通过索引提高数据检索效率,降低IO成本 ,但是用了索引也会降低更新的效率,每次修改都会导致我们的索引文件里面的信息发送变化,并且内存消耗up
索引也可以理解为一张表,里面的索引字段指向实体表记录
什么时候用索引
频繁作为查询条件的、关联查询的、分组排序的、唯一索引的
Expain性能分析
作用:
使用Explain关键字可以模拟优化器(就是之前那个Optimizer优化器)执行SQL查询语句,得到mysql是如何处理sql语句的,进行分析(查看执行计划)
使用:
分析字段:
id表示一趟独立的查询,一个sql的躺数越少越好
select_type
type
最关键三:range、index、all
key和key_len和rows
key_len如何计算索引长度
EXTRA
目的:减少全表扫描,增加性能
子查询(SUBQUERY):
范围查询(DEPENDENT SUBQUERY)
不可用缓存查询:
sql未命中,sql不一样——>当出现变量时,sql就肯定不一样了;
All问题:
All table scan,将全表进行遍历找到匹配的行;
index索引
出现index是sql使用了索引但是没有通过索引进行过滤,一般是使用了覆盖索引或者是利用索引进行排序分组;
范围查询:
group by先进行排序后进行分组
用了索引之后发现速度发生百倍优化(reset cache)
两个表关联,关联字段要建索引
where条件后的字段用了索引
统计数量count(*):MyISAM的话,他统计了表中数据的数量,InnoDB没有统计会真的去打开表进行扫描
EXPLAIN SELECT * FROM t_dept
字段解析 :
id指的是执行顺序,type指的是黄色红色黑色那些预警,key_len指的是where条件字段长度(长度越长,越容易命中),rows值的行数(物理扫描的行数,越少越好速度越快),Extra额外字段一般看group by,other by,关联查询;
插入100w数据如何做到最快
1.我们可以将100w条插入语句进行拼接,让他变为一条语句,速度肯定快一些
2.我们可以取消mysql的自动提交,因为100w条数据提交100w次和提交1次
肯定不一样;
3.使用多线程
mysql的主从复制
主机从机用一个binlog,里面有共有函数
1.创建函数(随机产生编号以及随机名字)
2.创建存储过程插入数据(利用上面两个函数得到随机编号以及名字)
CREATE TABLE `dept` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`deptName` VARCHAR(30) DEFAULT NULL,
`address` VARCHAR(40) DEFAULT NULL,
ceo INT NULL ,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `emp` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`empno` INT NOT NULL ,
`name` VARCHAR(20) DEFAULT NULL,
`age` INT(3) DEFAULT NULL,
`deptId` INT(11) DEFAULT NULL,
PRIMARY KEY (`id`)
#CONSTRAINT `fk_dept_id` FOREIGN KEY (`deptId`) REFERENCES `t_dept` (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
#开启自定义函数配置的开启
SET GLOBAL log_bin_trust_function_creators=1;
#随机生成字符串函数
DELIMITER $$
CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255)
BEGIN
DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
DECLARE return_str VARCHAR(255) DEFAULT '';
DECLARE i INT DEFAULT 0;
WHILE i < n DO
SET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));
SET i = i + 1;
END WHILE;
RETURN return_str;
END $$
USE mydb
#用于随机产生多少到多少的编号
DELIMITER $$
CREATE FUNCTION rand_num (from_num INT ,to_num INT) RETURNS INT(11)
BEGIN
DECLARE i INT DEFAULT 0;
SET i = FLOOR(from_num +RAND()*(to_num -from_num+1)) ;
RETURN i;
END$$
#假如要删除
#drop function rand_num;
#假如要删除
#drop function rand_string;
#插入五十万条数据
DELIMITER $$
CREATE PROCEDURE insert_emp( START INT , max_num INT )
BEGIN
DECLARE i INT DEFAULT 0;
#set autocommit =0 把autocommit设置成0,关闭自动提交
SET autocommit = 0;
REPEAT
SET i = i + 1;
INSERT INTO emp (empno, NAME ,age ,deptid ) VALUES ((START+i) ,rand_string(6) , rand_num(30,50),rand_num(1,10000));
UNTIL i = max_num
END REPEAT;
COMMIT;
END$$
#删除
# DELIMITER ;
# drop PROCEDURE insert_emp;
#执行存储过程,往dept表添加随机数据
DELIMITER $$
CREATE PROCEDURE `insert_dept`( max_num INT )
BEGIN
DECLARE i INT DEFAULT 0;
SET autocommit = 0;
REPEAT
SET i = i + 1;
INSERT INTO dept ( deptname,address,ceo ) VALUES (rand_string(8),rand_string(10),rand_num(1,500000));
UNTIL i = max_num
END REPEAT;
COMMIT;
END$$
#删除
# DELIMITER ;
# drop PROCEDURE insert_dept;
#插入1w条数据
#执行存储过程,往dept表添加1万条数据
DELIMITER ;
CALL insert_dept(10000);
#执行存储过程,往emp表添加50万条数据
DELIMITER ;
CALL insert_emp(100000,500000);
SELECT COUNT(*) FROM emp;
SELECT COUNT(*) FROM dept;
像这么多数据,我们进行查询就需要用到索引了,我们要执行下一个sql就要删除当前sql的索引
流程:
需要mysql承认你取出来的字符串
1. 查看表中索引
SHOW INDEX FROM t_emp;
2.我们的索引也是一张表,在information数据库中,名字为STATISTICS
查看一下索引表,主键索引不能删除
3.创建索引
单字段下
先查询一下,发现explain估算49w多行
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.`age`=30;
CREATE INDEX idx_age ON emp(age);
创建完索引后,就只有4w行了,速度up
0.03->0.007
多字段下
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 AND deptid=4 AND emp.name = 'abcd';
CREATE INDEX idx_age_deptid_name ON emp(age,deptid,NAME);
速度由0.082->忽略不计
用图表示多字段索引的执行
最佳左前缀:从左边到右边按顺序执行,不然会断开
如果系统经常出现的sql如下:
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 AND emp.name = 'abcd'
或者
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.deptid=1 AND emp.name = 'abcd'
那原来的idx_age_deptid_name 还能否正常使用?
第二个不能正常执行,没有遵循从左到右的顺序执行 ,需要环环命中——>同时也体现出全值匹配,字段与索引一定要对应
练习
#执行删除
CALL proc_drop_index("mydb","emp");
#在索引表中查询指定索引 (非主键)
SELECT index_name FROM information_schema.`STATISTICS` WHERE TABLE_NAME='t_emp'
AND TABLE_SCHEMA='mydb' AND INDEX_NAME <>'PRIMARY' AND SEQ_IN_INDEX=1;
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.`age`=30; #0.03 0.007
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 AND deptid=4
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 AND deptid=4 AND emp.name = 'abcd';
#创建索引
CREATE INDEX idx_age ON emp(age);
CREATE INDEX idx_age_deptid_name ON emp(age,deptid,NAME);
SHOW INDEX FROM emp;
#模糊查询
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.`name` LIKE 'abc%';#0.8->0.016
#这种会导致索引失效,别用函数
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE LEFT(emp.`name`,3)='abc';#0.8
#创建索引
CREATE INDEX idx_name ON emp(NAME);
#执行删除
CALL proc_drop_index("mydb","emp");
CALL proc_drop_index("mydb","dept");
#范围查询,范围右边的字段索引是失效的(这种右边是根据索引来判断的)
EXPLAIN SELECT SQL_NO_CACHE * FROM emp #0.5->0.052,type:range
WHERE emp.age=30 AND emp.deptId>20 AND emp.name = 'abc' ; #最佳效率0.004
#创建索引
CREATE INDEX idx_age_deptid_name ON emp(age,deptid,NAME);
CREATE INDEX idx_age_deptid_name ON emp(age,NAME,deptid);
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.`name` <> 'abc';
#创建索引,对于上述失效!=会导致索引失效
CREATE INDEX idx_name ON emp(NAME);
EXPLAIN SELECT * FROM emp WHERE age IS NULL #0.2->0.001
#这种为not都会失效
EXPLAIN SELECT * FROM emp WHERE age IS NOT NULL;#0.04->0.009,索引失效,type为ALL
#创建索引
CREATE INDEX idx_age ON emp(age);
#我们的索引结构平衡树是按照a-z,如果首字母都不能确定,索引就会失效
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.`name` LIKE '%abc%';#0.329->0.274
#创建索引
CREATE INDEX idx_name ON emp(NAME);
#执行删除
CALL proc_drop_index("mydb","emp");
CALL proc_drop_index("mydb","dept");
#类型转换也会造成索引失效
#有几个字段就建立几个字段的索引
索引是如何找到数据的
(24条消息) (3)MySQL是如何通过【索引】找到一条【真实的数据】_孤鸿寄语LWQ的博客-CSDN博客_mysql如何通过索引查询
注意事项
注意sql编写,防止索引失效
小总结
1. 记得最佳左前法则
2.不能使用函数:abs,max,<>....
3.不能用like前缀%xxx通配符
4.is not null不行
5.类型转换也不行
一些建议
1.当选择组合索引时,我们可以将过滤性较好的字段放在索引字段靠前位置,因为这样筛选出来到下一个树,可能节点就相对变少了,甚至为1,效率更高;
2.当选择组合索引,要尽量包含where后更多字段
3.尽量避免索引失效问题
关联查询
场景:
当两个表没有关联字段,然后进行关联查询,会两个表都进行全局扫描,从而出现笛卡尔积
如何关联:
当在关联查询场景下,我们关联查询->首先会扫描驱动表的第一行数据,然后根据第一行数据对被驱动表进行扫描,找到的数据合为一行为总的一行数据;
结论:
1.驱动表是一定会被全局扫描的,而被驱动表不一定,所以我们索引建在被驱动表上,驱动表因为一定全部被扫所以建不建索引是无所谓的;
2.为了提升效率,我们数据量相对较小的最好作为驱动表
3.另外,inner join和left join不太一样,在inner join下mysql会自动选择那个为被驱动表,而不是它们的相对位置,是根据小结果集的作为驱动表;
关联查询实例
关联查询一下两个表 ->extra出现两表之间没有关联字段,查很慢,出现笛卡尔
EXPLAIN SELECT * FROM class LEFT JOIN book ON class.`card`=book.`card`;
#创建索引,这里我们一般都是给被驱动表建立索引
CREATE INDEX Y ON book(card);
#执行删除
CALL proc_drop_index("mydb","book");
DROP INDEX Y ON book;
DROP INDEX X ON class;
#创建索引
ALTER TABLE class ADD INDEX X (card);
#inner join,mysql自己选择哪个是被驱动表——>根据索引进行判断,谁有索引就谁是被驱动
#小数据为驱动表,扫描时间短以此提高效率
#求所有dept对应的CEO名称
#1.这里会发现是一趟查询,mysql5.7的一个优化,c表为驱动表,我们这个被驱动表为ab虚拟表
#而虚拟表又不能创建索引,所以说会浪费一次优化机会,5.7更新所在之处
EXPLAIN SELECT c.`name`,ab.name ceoname FROM t_emp c LEFT JOIN
(SELECT b.`id`,a.`name` FROM t_emp a INNER JOIN t_dept b ON a.`id`=b.`CEO`)ab
ON c.`deptld`=ab.id;
#得到dept的掌门
SELECT b.`id`,a.`name` FROM t_emp a INNER JOIN t_dept b ON a.`id`=b.`CEO`
#2.先查询名字和CEO
SELECT ab.name,c.`name` ceoname FROM
(SELECT a.`name`,b.`CEO` FROM t_emp a LEFT JOIN t_dept b ON a.`deptld`=b.`id`) ab
LEFT JOIN t_emp c ON ab.ceo=c.`id`;
#3.最快,直接关联,不用子查询一次性两次外连接得到帮派派主(第一次得到用户那边信息,第二次根据CEO进行筛选)
EXPLAIN SELECT a.`name`,c.`name` ceoname FROM t_emp a
LEFT JOIN t_dept b ON a.`deptld`=b.`id`
LEFT JOIN t_emp c ON b.`CEO`=c.`id`;
关联查询小结论:
1.我们需要保证被驱动表join的字段以及被索引
2.left join时,选择小表为驱动
3.inner join:小结果集作为驱动表
4.子查询尽量不要放在驱动表,因为5.7前虚拟表是不能用索引的,会导致效率降低
5.能直接关联就直接关联
关联优化测试
这里明显有not导致索引不能使用,优化->使用left join进行关联查询,然后根据条件过滤即可
#至少两个非掌门成员的门派(先掌门编号,然后根据掌门编号在t_emp中查)
SELECT * FROM t_emp a WHERE a.id NOT IN
(SELECT b.CEO FROM t_dept b WHERE b.CEO IS NOT NULL);
#优化(先得到所有掌门(left join),然后条键过滤)
SELECT * FROM t_emp a LEFT JOIN t_dept b ON a.id = b.CEO
WHERE b.id IS NULL;
索引对于分组查询的影响
(24条消息) 【mysql知识点整理】--- order by 、group by 出现Using filesort原因详解_nrsc的博客-CSDN博客_filesort 原因
总结:
1.分组查询order by后的字段能否使用索引->取决于后面是否接了过滤条件,如果接了则索引生效
2.order by后面的顺序是很重要的,顺序不一样结果不一样,所以并不会被优化
3.如果字段都升序或者降序是不影响结果的,如果不一致就会影响从而出现using filesort
#执行删除
CALL proc_drop_index("mydb","emp");
CALL proc_drop_index("mydb","dept");
#分组查询
CREATE INDEX idx_age_deptid_name ON emp (age,deptid,NAME)
CREATE INDEX idx_age_deptid_empno ON emp (age,deptid,empno);
#以下是否能使用到索引,能否去掉using filesort ,(order by想用索引必须要过滤条件)
EXPLAIN SELECT SQL_NO_CACHE * FROM emp ORDER BY age,deptid;
EXPLAIN SELECT SQL_NO_CACHE * FROM emp ORDER BY age,deptid LIMIT 10;
#无过滤 不索引
EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY deptid;
EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY deptid,NAME;
EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY deptid,empno;
#deptid字段需要再name前面,这顺序并不会被优化,因为结果会被影响,order by后面字段顺序是很重要的
EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY NAME,deptid;
EXPLAIN SELECT * FROM emp WHERE deptid=45 ORDER BY age;
#顺序错,必排序,可以都是降序或者升序,这样的话,顺序改一下还是不影响结果的
EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY deptid DESC, NAME DESC ;
EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY deptid ASC, NAME DESC ;
#方向反 必排序,一升一降不能索引:Using filesort
排序分组优化
mysql会对索引的选择进行优化,选择一个自认为最快的索引
如果不在字段不在索引列上,filesort有两种算法
1.双路排序:就是两次扫描磁盘,先把所有内容扫一遍放到磁盘,扫完后再对磁盘中的内容进行排序(也就是读取行指针和order by列),对磁盘两次扫描,IO很耗时
2.单路排序:从磁盘上读取查询的索引列,然后按照order by进行查询,他把每次读取的内容放到内存中,减少了IO的损耗
group by与other by的区别就是:
group by可以没有限制条件就是用索引,other by无过滤不索引
还一个很优化的点(覆盖索引):
之前不是出现模糊查询like %xx、is not、other by xxx这些都会导致索引失效嘛,我们可以对查询的内容进行限制,不再是select * ,而是字段限制了,这样可以根据字段来匹配索引,以此提高效率;
CREATE INDEX idx_id_age_deptid ON emp(id,age,deptid);
#可以对查询内容上索引
EXPLAIN SELECT SQL_NO_CACHE NAME FROM emp WHERE age IS NOT NULL;
EXPLAIN SELECT * FROM emp WHERE NAME LIKE '%abc';
EXPLAIN SELECT SQL_NO_CACHE id,age,deptid FROM emp WHERE NAME LIKE '%abc';
#查看索引
SHOW INDEX FROM emp;
作业(sql练习+优化)
注意:Group by的字段设置之后,前面select的字段只能包含Group by的内容和函数内容,否则会报错
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE age =30 AND empno <101000 ORDER BY NAME ;#0.729
#执行删除
CALL proc_drop_index("mydb","emp");
CALL proc_drop_index("mydb","dept");
#建立索引,优先第一个idx_age_empno的索引,mysql会优选择最优的索引
CREATE INDEX idx_age_empno ON emp(age,empno);
CREATE INDEX idx_age_name ON emp (age,NAME);
CREATE INDEX idx_age ON emp(age);
CREATE INDEX idx_name ON emp(NAME);
CREATE INDEX idx_id_age_deptid ON emp(id,age,deptid);
#可以对查询内容上索引
EXPLAIN SELECT SQL_NO_CACHE NAME FROM emp WHERE age IS NOT NULL;
EXPLAIN SELECT * FROM emp WHERE NAME LIKE '%abc';
EXPLAIN SELECT SQL_NO_CACHE id,age,deptid FROM emp WHERE NAME LIKE '%abc';
#查看索引
SHOW INDEX FROM emp;
#1.求小弟比门派派主年龄小的信息
SELECT a.name FROM t_emp a
LEFT JOIN t_dept b ON a.`deptld`=b.id
LEFT JOIN t_emp c ON b.CEO=c.`id`
WHERE c.`age`<a.`age`;
#优化
EXPLAIN SELECT SQL_NO_CACHE a.`name`,a.`age`,c.`name`,c.`age` FROM emp a
LEFT JOIN dept b ON a.`deptId`=b.`id`
LEFT JOIN emp c ON b.`ceo`=c.`id`
WHERE c.`age`<a.`age`;
#2.列出年龄比帮派平均年龄小的人员(先得到部门分组的人员信息)
SELECT c.`name`,c.`age` FROM t_emp c INNER JOIN
(SELECT a.`deptld`,AVG(a.`age`) avgage FROM t_emp a WHERE a.`deptld` IS NOT NULL
GROUP BY a.`deptld`)aa
ON c.`deptld`=aa.deptld
WHERE c.`age`<aa.avgage;
#优化,将这个子查询作为驱动表
#因为子查询5.7版本前是不能有索引的,所以我们把它作为驱动表,这样非驱动表就可以上索引
EXPLAIN SELECT SQL_NO_CACHE c.`name`,c.`age`,aa.avgage FROM emp c
INNER JOIN
(SELECT a.deptId,AVG(a.age)avgage FROM emp a WHERE a.deptId IS NOT NULL
GROUP BY a.deptId)aa
ON c.`deptId`=aa.deptId
WHERE c.`age`<aa.avgage;
#创建索引
CREATE INDEX idx_deptId ON emp(deptId);
CREATE INDEX idx_deptId_age ON emp(deptId,age);
#3.列出至少有2个年龄>40岁的成员的门派 (select得到数量,肯定是group by了)
#(先按照门派分组 ->然后进行筛选得到>40岁的员工数量 —>最后进行判断)
SELECT b.`deptName`,b.`id`,COUNT(*) FROM t_emp a
INNER JOIN t_dept b ON a.`deptld`=b.`id`
WHERE a.`age`>40
GROUP BY b.`deptName`,b.`id`
HAVING COUNT(*)>=2;
#优化
EXPLAIN SELECT SQL_NO_CACHE b.`deptName`,b.`id`,COUNT(*) FROM dept b
STRAIGHT_JOIN emp a ON a.`deptId`=b.`id`
WHERE a.`age`>40
GROUP BY b.`deptName`,b.`id`
HAVING COUNT(*)>=2;
#建立索引
CREATE INDEX idx_deptName ON dept(deptName);
CREATE INDEX idx_deptId_age ON emp(deptId,age);
#4.非掌门人员(先查询所有有帮派的帮派,然后提取CEO,然后not in)
SELECT * FROM t_emp a WHERE a.`id` NOT IN
(SELECT b.`CEO` FROM t_dept b WHERE b.`CEO` IS NOT NULL)
;
SELECT * FROM t_emp
SELECT * FROM t_dept
#优化:(1.得到非掌门的门派成员信息,采用左外关联查询,门派表没有匹配的就会null,所以要b.id is null)
SELECT * FROM t_emp a
LEFT JOIN t_dept b ON a.`id`=b.`CEO`
WHERE b.`id` IS NULL;
SELECT c.deptName,c.id,COUNT(*)
FROM t_emp a INNER JOIN t_dept c ON a.`deptld`=c.id
LEFT JOIN t_dept b ON a.`id`=b.`CEO`
WHERE b.`id` IS NULL
GROUP BY c.deptName,c.id
HAVING COUNT(*)>=2
;
#5.得到所有在帮派的成员->得到在籍帮派的名字和id->在关联一次,去除掌门,留下非掌门的信息(利用左外的性质)
#要得到数量,所以分组
EXPLAIN SELECT SQL_NO_CACHE c.`deptName`,c.`id`,COUNT(*) FROM emp a
INNER JOIN dept c ON a.`deptId`=c.`id`
LEFT JOIN dept b ON a.`id`=b.`CEO`
WHERE b.`id` IS NULL
GROUP BY c.`deptName`,c.`id`
HAVING COUNT(*)>=2;
#创建索引
CREATE INDEX idx_deptName ON dept(deptName);
CREATE INDEX idx_deptId ON emp(deptId);
CREATE INDEX idx_CEO ON dept(CEO);
#6.列出所有人员,并且增加一列备注是否为掌门,如果是备注就是——>case when 判断
#然后利用左外性质b的id->is null then xxx进行判断
SELECT a.`name`,a.`age`,b.`deptName`,(CASE WHEN b.id IS NULL THEN '否' ELSE '是' END)'是否为掌门'
FROM t_emp a
LEFT JOIN t_dept b ON a.`id`=b.`CEO`;
#7.列出所有门派,并且备注,平均年龄>50就是老鸟,否则为菜鸟
SELECT b.`deptName`,b.`id`,IF(AVG(a.`age`)>50,'老鸟','菜鸟')'老鸟or菜鸟'
FROM t_emp a
INNER JOIN t_dept b ON a.`deptld`=b.`id`
GROUP BY b.`deptName`,b.`id`;
#8.显示每个门派年龄最大的人(->先得到最大年龄根据门派进行分组->然后关联一下人物表得到最大年龄的人)
SELECT c.`name`,c.`age`,aa.maxage FROM t_emp c INNER JOIN
(SELECT a.`deptld`,MAX(a.`age`)maxage
FROM t_emp a WHERE a.`deptld` IS NOT NULL
GROUP BY a.`deptld`)aa
ON c.`deptId`=aa.deptld AND c.`age`=aa.maxage;
#9.求每个门派第三大年龄的人(w写错了)
SELECT a.`age`,a.`name`,a.`deptld` FROM t_emp a ORDER BY a.`age` DESC
LEFT JOIN(
SELECT a.`id` FROM t_emp a INNER JOIN t_dept b ON a.`deptld`=b.id
)aa ON a.`deptld`=aa.id;#这里就分组错了,原计划分组后再limit完成
边栏推荐
- 延时队列`DelayQueue`
- [Kevin's third play in a row] is rust really slower than C? Further analyze queen micro assessment
- js打印99乘法表
- 通过uview让tabbar根据权限显示相应数量的tabbar
- Delay queue `delayqueue`
- JS uses the while cycle to calculate how many years it will take to grow from 1000 yuan to 5000 yuan if the interest rate for many years of investment is 5%
- 在线文本数字识别列表求和工具
- 语音信号处理-概念(四):傅里叶变换、短时傅里叶变换、小波变换
- js例题打印1-100之间所有7的倍数的个数及总和
- (已解决) npm突然报错 Cannot find module ‘D:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js‘
猜你喜欢
Multi table associated query -- 07 -- hash join
JS use switch to output whether the result is qualified
JS to determine whether the number entered by the user is a prime number (multiple methods)
js输出形状
【软件工程】山东大学软件工程复习提纲
IDEA连接数据库报错
JS print 99 multiplication table
How to view program running time (timer) in JS
Solve the problem of win10 wsl2 IP change
认识O(NlogN)的排序
随机推荐
通过uview让tabbar根据权限显示相应数量的tabbar
R 中的 RNA-Seq 数据分析 - 调查数据中的差异表达基因!
apifox学习
js用switch语句根据1-7输出对应英文星期几
(已解决) npm突然报错 Cannot find module ‘D:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js‘
log4j:WARN No such property [zipPermission] in org.apache.log4j.RollingFileAppender.
使用 Blackbox Exporter 测试网络连通性
Websocket database listening
yarn create vite 报错 ‘D:\Program‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件
SQL attendance query interval: one hour
攻防演习防御体系构建之第一篇之介绍和防守的四个阶段
Yarn create vite reports an error 'd:\program' which is neither an internal or external command nor a runnable program or batch file
2022 cisp-pte (II) SQL injection
无论LCD和OLED显示技术有多好,都无法替代这个古老的显示数码管
JS to determine whether the result is qualified, the range is 0-100, otherwise re-enter
What is the difference between volatile and synchronized?
How torch.gather works
Rust Async: smol源码分析-Executor篇
Use uview to enable tabbar to display the corresponding number of tabbars according to permissions
JDBC transaction commit case