以下均是自己学习时的一些总结或者遇到问题的解决办法
//in
select * from A where id in(select id from B)
以上查询使用了in语句,in()只执行一次,它查出B表中的所有id字段并缓存起来.之后,检查A表的id是否与B表中的id相等,如果相等则将A表的记录加入结果集中,直到遍历完A表的所有记录.
它的查询过程类似于以下过程
List resultSet=[];
Array A=(select * from A); //把A表数据查询出来
Array B=(select id from B); //把B表符合要求的数据查出来
//遍历A数据,和B查出来的数据一个一个对比,符合要求的结果集就是需要的
for(int i=0;i<A.length;i++) {
for(int j=0;j<B.length;j++) {
if(A[i].id==B[j].id) {
resultSet.add(A[i]);
break;
}
}
}
return resultSet;
in适合B表比A表数据小的情况
exists
select a.* from A a where exists(select 1 from B b where a.id=b.id)
以上查询使用了exists语句,exists()会执行A.length次,它并不缓存exists()结果集,
因为exists()结果集的内容并不重要,重要的是结果集中是否有记录,如果有则返回true,没有则返回false.
它的查询过程类似于以下过程
List resultSet=[];
Array A=(select * from A) //查询A表所有数据
for(int i=0;i<A.length;i++) {
if(exists(A[i].id) { //执行select 1 from B b where b.id=a.id是否有记录返回
resultSet.add(A[i]);
}
}
return resultSet;
exists适合B表比A表数据大的情况
结论:in先计算子查询的结果,然后以该结果集为源头和主语句发生关联关系;
exists先计算主语句的结果集,在和子查询寻发生关联关系
所以:子查询结果集小,in更适用;反之,若主查询结果集小,则用exists
union: 对两个结果集进行
并集操作
, 不包括重复行,相当于distinct, 同时进行默认规则的排序;(连接两个结果集,并且去重)
union all: 对两个结果集进行并集操作, 包括重复知行, 即所有的结果全部显示, 不管是不是重复;(连接两个结果集,不去重)
union内部的select语句必须拥有相同数量的列,列也必须拥有相似的数据类型,同时,每条select语句中列的顺序必须相同
这几天改了个bug,公司项目是mysql5版本的,但现在有用mysql8版本的,发生了sql报错,主要是因为部分列名在mysql5不是关键字,mysql8是关键字,导致sql执行报错;具体解决方式,在执行的sql中,给关键字加上反引号``(ESC下面的那个键)
,比如:
//此语句在mysql5中执行时没问题的,因为id和groups均不是关键字,
//但在mysql8中groups是关键字,执行就会报错
insert into t_table (id,groups) values(1,'test');
//mysql8中执行时,给groups加上反引号
insert into t_table (id,`groups`) values(1,'test');
注意:select * from t_table是不会报错的,但只要带groups时就会报错
组合索引,是在按一定顺序的多个字段上创建的索引。多个字段的排序不同,索引的使用不同。即 index_name (a, b)和 index_name2 (b, a)是不同的索引。
组合唯一索引也遵循组合索引的使用规则
举例说明,假设有如下一个MySQL表:
create table tb_person_info (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`name` varchar(255) NOT NULL COMMENT '姓名',
`age` int DEFAULT '0' COMMENT '年龄',
`birthday` date DEFAULT NULL COMMENT '出生日期',
`sex` varchar(10) DEFAULT NULL COMMENT '性别',
`id_card` char(18) DEFAULT NULL COMMENT '身份证号',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入库时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
PRIMARY KEY (`id`),
KEY `idx_name_age_card` (`name`, `age`, `id_card`),
KEY `idx_id_card` (`id_card`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='人员信息';
在该表上有创建三个索引,分别是:
下面展示一些SQL语句,并标明是否用到索引,以及用到了哪个索引
# 用到索引idx_name_age_carcd
select * from tb_person_info where name = '张伟';
# 没有用到索引
select * from tb_person_info where age = 25;
# 用到索引idx_id_card
select * from tb_person_info where id_card like '4110812022%';
# 用到索引idx_name_age_card
select * from tb_person_info where name = '张伟' and age = 25;
# 用到索引idx_name_age_card
select * from tb_person_info where name = '张伟' and id_card like '411081%';
# 用到索引idx_id_card
select * from tb_person_info where age = 25 and id_card like '411081%';
# 用到索引idx_name_age_card
select age, id_card from tb_person_info where age = 25 and id_card like '411081%';
总结以上SQL语句可以得到一下结论:
查询字段有组合索引之外的字段
时,查询条件必须包含组合索引中的第一个字段
,才会用到该索引
查询字段只限于组合索引内的字段
时,查询条件只要有组合索引中的字段
,就会用到该索引
当创建(a,b,c)复合索引时,想要索引生效的话,只能使用 a和ab、ac和abc三种组合!但如果是ba、ca也是会用到索引的,这是mysql查询优化器,mysql查询优化器会判断纠正这条sql语句该以什么样的顺序执行效率最高,最后才生成真正的执行计划
,也就是说,即使写的顺序是ba/ca,但最后真正执行的顺序还是ab/ac;ab是用到了a和b两个索引,ac只用到了a索引。见下图:
索引失效的情况:
from-->on-->join-->where-->group by-->avg,sum.... -->having-->select-->distinct-->order by-->limit