广西住房建设部网站,重庆装修网,天津市网站制作 公司,建站最好的公司排名数据库数据库的三范式是什么drop、delete、truncate 分别在什么场景之下使用char 和 varchar 的区别是什么数据库的乐观锁和悲观锁是什么SQL 约束有哪几种mysql 的内连接、左连接、右连接有什么区别MyIASM和Innodb两种引擎所使用的索引的数据结构是什么mysql 有关权限的表都有哪…
数据库数据库的三范式是什么drop、delete、truncate 分别在什么场景之下使用char 和 varchar 的区别是什么数据库的乐观锁和悲观锁是什么SQL 约束有哪几种mysql 的内连接、左连接、右连接有什么区别MyIASM和Innodb两种引擎所使用的索引的数据结构是什么mysql 有关权限的表都有哪几个MySQL中InnoDB引擎的行锁是通过加在什么上完成Oracle和Mysql的区别MyISAM和InnoDB区别索引相关问题事务相关问题SQL语句在MySQL中如何执行SQL 优化数据库的三范式是什么
第一范式列不可再分第二范式属性完全依赖于主键第三范式任何非主属性不依赖于其它非主属性
drop、delete、truncate 分别在什么场景之下使用
不再需要一张表的时候用drop想删除部分数据行时候用delete并且带上where子句保留表而删除所有数据的时候用truncate
char 和 varchar 的区别是什么
Char是一种固定长度的类型varchar是一种可变长度的类型
数据库的乐观锁和悲观锁是什么
悲观锁假定会发生并发冲突屏蔽一切可能违反数据完整性的操作 在查询完数据的时候就把事务锁起来直到提交事务实现方式使用数据库中的锁机制 乐观锁假设不会发生并发冲突只在提交操作时检查是否违反数据完整性。 在修改数据的时候把事务锁起来通过version的方式来进行锁定实现方式使用version版本或者时间戳 SQL 约束有哪几种
主键约束非空唯一外键约束外键字段必须引用于主键字段被引用的表称为主表引用的表称为从表唯一约束非空约束检查约束
mysql 的内连接、左连接、右连接有什么区别
内连接显示两个表中有联系的所有数据左链接以左表为参照显示左边所有数据右表中没有则以null显示右链接以右表为参照显示右边所有数据左表中没有则以null显示
MyIASM和Innodb两种引擎所使用的索引的数据结构是什么
都是B树
MyIASM引擎B树的数据结构中存储的内容实际上是实际数据的地址值。也就是说它的索引和实际数据是分开的只不过使用索引指向了实际数据。这种索引的模式被称为非聚集索引。
Innodb引擎的索引的数据结构也是B树只不过数据结构中存储的都是实际的数据这种索引有被称为聚集索引。
mysql 有关权限的表都有哪几个
user权限表记录允许连接到服务器的用户帐号信息里面的权限是全局级的。db权限表记录各个帐号在各个数据库上的操作权限。table_priv权限表记录数据表级的操作权限。columns_priv权限表记录数据列级的操作权限。host权限表配合db权限表对给定主机上数据库级操作权限作更细致的控制。这个权限表不受GRANT和REVOKE语句的影响。
MySQL中InnoDB引擎的行锁是通过加在什么上完成
InnoDB是基于索引来完成行锁
Oracle和Mysql的区别
在Mysql中一个用户下可以创建多个库 而在Oracle中Oracle服务器是由两部分组成
数据库实例【理解为对象看不见的】数据库【理解为类看得见的】
一个数据库实例可拥有多个用户一个用户默认拥有一个表空间。表空间是存储我们数据库表的地方表空间内可以有多个文件。 当我们使用Oracle作为我们数据库时我们需要指定用户、表空间来存储我们所需要的数据
MyISAM和InnoDB区别
MyISAM是MySQL的默认数据库引擎5.5版之前。5.5版本之后MySQL引入了InnoDB事务性数据库引擎MySQL5.5版本后默认的存储引擎为InnoDB。
是否支持行级锁 MyISAM 只有表级锁InnoDB 支持行级锁和表级锁默认为行级锁。是否支持事务和崩溃后的安全恢复 MyISAM 强调的是性能每次查询具有原子性其执行速度比InnoDB类型更快但是不提供事务支持。但是InnoDB 提供事务支持事务外部键等高级数据库能。 是具有事务、回滚和崩溃修复能力的事务安全型表。是否支持外键 MyISAM不支持InnoDB支持。是否支持MVCC 仅 InnoDB 支持。MVCC意思为多版本并发控制应对高并发事务MVCC比单纯的加锁更⾼效MVCC只在读已提交RC 和 可重复读RR 两个隔离级别下工作。用更好的方式去处理读写冲突。
索引相关问题
https://blog.csdn.net/yy139926/article/details/124443946
事务相关问题
https://blog.csdn.net/yy139926/article/details/124582264
SQL语句在MySQL中如何执行 连接器
主要负责用户登录数据库进行用户的身份认证包括校验账户密码权限等操作如果用户账户密码已通过连接器会到权限表中查询该用户的所有权限之后在这个连接里的权限逻辑判断都是会依赖此时读取到的权限数据也就是说后续只要这个连接不断开即时管理员修改了该用户的权限该用户也是不受影响的。
查询缓存(MySQL 8.0 版本后移除)
查询缓存主要用来缓存我们所执行的 SELECT 语句以及该语句的结果集。
连接建立后执行查询语句的时候会先查询缓存MySQL 会先校验这个 sql 是否执行过以 Key-Value 的形式缓存在内存中Key 是查询预计Value 是结果集。如果缓存 key 被命中就会直接返回给客户端如果没有命中就会执行后续的操作完成后也会把结果缓存起来方便下一次调用。当然在真正执行缓存查询的时候还是会校验用户的权限是否有该表的查询条件。
MySQL 查询不建议使用缓存因为查询缓存失效在实际业务场景中可能会非常频繁假如你对一个表更新的话这个表上的所有的查询缓存都会被清空。对于不经常更新的数据来说使用缓存还是可以的。所以一般在大多数情况下我们都是不推荐去使用查询缓存的。
分析器
MySQL 没有命中缓存那么就会进入分析器分析器主要是用来分析 SQL 语句是来干嘛的分析器也会分为几步
第一步词法分析一条 SQL 语句有多个字符串组成首先要提取关键字比如 select提出查询的表提出字段名提出查询条件等等。做完这些操作后就会进入第二步。
第二步语法分析主要就是判断你输入的 sql 是否正确是否符合 MySQL 的语法。
完成这 2 步之后MySQL 就准备开始执行了但是如何执行怎么执行是最好的结果呢这个时候就需要优化器上场了。
优化器
优化器的作用就是它认为的最优的执行方案去执行比如多个索引的时候该如何选择索引多表查询的时候如何选择关联顺序等。可以说经过了优化器之后可以说这个语句具体该如何执行就已经定下来。
执行器
当选择了执行方案后MySQL 就准备开始执行了首先执行前会校验该用户有没有权限如果没有权限就会返回错误信息如果有权限就会去调用引擎的接口返回接口执行的结果。
SQL 优化
避免使用select *
很多时候我们写sql语句时为了方便喜欢直接使用select *一次性查出表中所有列的数据。
反例
select * from user where id1;在实际业务场景中可能我们真正需要使用的只有其中一两列。查了很多数据但是不用白白浪费了数据库资源比如内存或者cpu。
此外多查出来的数据通过网络IO传输的过程中也会增加数据传输的时间。
还有一个最重要的问题是select *不会走覆盖索引会出现大量的回表操作而从导致查询sql的性能很低。
那么如何优化呢
正例
select name,age from user where id1;用union all代替union
我们都知道sql语句使用union关键字后可以获取排重后的数据。
而如果使用union all关键字可以获取所有数据包含重复的数据。
反例
(select * from user where id1)
union
(select * from user where id2);排重的过程需要遍历、排序和比较它更耗时更消耗cpu资源。
所以如果能用union all的时候尽量不用union。
正例
(select * from user where id1)
union all
(select * from user where id2);除非是有些特殊的场景比如union all之后结果集中出现了重复数据而业务场景中是不允许产生重复数据的这时可以使用union。
小表驱动大表也就是说用小表的数据集驱动大表的数据集
假如有order和user两张表其中order表有10000条数据而user表有100条数据。
这时如果想查一下所有有效的用户下过的订单列表。
可以使用in关键字实现
select * from order
where user_id in (select id from user where status1)也可以使用exists关键字实现
select * from order
where exists (select 1 from user where order.user_id user.id and status1)前面提到的这种业务场景使用in关键字去实现业务需求更加合适。
为什么呢
因为如果sql语句中包含了in关键字则它会优先执行in里面的子查询语句然后再执行in外面的语句。如果in里面的数据量很少作为条件查询速度更快。
而如果sql语句中包含了exists关键字它优先执行exists左边的语句即主查询语句。然后把它作为条件去跟右边的语句匹配。如果匹配上则可以查询出数据。如果匹配不上数据就被过滤掉了。
这个需求中order表有10000条数据而user表有100条数据。order表是大表user表是小表。如果order表在左边则用in关键字性能更好。
总结一下
in 适用于左边大表右边小表。exists 适用于左边小表右边大表。
不管是用in还是exists关键字其核心思想都是用小表驱动大表。
批量操作
如果你有一批数据经过业务处理之后需要插入数据该怎么办
反例
for(Order order: list){orderMapper.insert(order):
}在循环中逐条插入数据。
insert into order(id,code,user_id)
values(123,001,100);该操作需要多次请求数据库才能完成这批数据的插入。
但众所周知我们在代码中每次远程请求数据库是会消耗一定性能的。而如果我们的代码需要请求多次数据库才能完成本次业务功能势必会消耗更多的性能。
那么如何优化呢
正例
orderMapper.insertBatch(list):提供一个批量插入数据的方法。
insert into order(id,code,user_id)
values(123,001,100),(124,002,100),(125,003,101);这样只需要远程请求一次数据库sql性能会得到提升数据量越多提升越大。
但需要注意的是不建议一次批量操作太多的数据如果数据太多数据库响应也会很慢。批量操作需要把握一个度建议每批数据尽量控制在500以内。如果数据多于500则分多批次处理。
多用limit
有时候我们需要查询某些数据中的第一条比如查询某个用户下的第一个订单想看看他第一次的首单时间。
select id, create_date from order
where user_id123
order by create_date asc;根据用户id查询订单按下单时间排序先查出该用户所有的订单数据得到一个订单集合。然后在代码中获取第一个元素的数据即首单的数据就能获取首单时间。
ListOrder list orderMapper.getOrderList();
Order order list.get(0);虽说这种做法在功能上没有问题但它的效率非常不高需要先查询出所有的数据有点浪费资源。
那么如何优化呢
正例
select id, create_date from order
where user_id123
order by create_date asc
limit 1;使用limit 1只返回该用户下单时间最小的那一条数据即可。此外在删除或者修改数据时为了防止误操作导致删除或修改了不相干的数据也可以在sql语句最后加上limit。
例如
update order set status0,edit_timenow(3)
where id100 and id200 limit 100;这样即使误操作比如把id搞错了也不会对太多的数据造成影响。
SQL查找是否存在别再count了
根据某一条件从数据库表中查询 『有』与『没有』只有两种状态那为什么在写SQL的时候还要SELECT count(*) 呢
无论是刚入道的程序员新星还是精湛沙场多年的程序员老白都是一如既往的count
反例目前多数人的写法
多次REVIEW代码时发现如现现象
业务代码中需要根据一个或多个条件查询是否存在记录不关心有多少条记录。普遍的SQL及代码写法如下
#### SQL写法:
SELECT count(*) FROM table WHERE a 1 AND b 2#### Java写法:
int nums xxDao.countXxxxByXxx(params);
if ( nums 0 ) {//当存在时执行这里的代码
} else {//当不存在时执行这里的代码
}推荐写法如下
#### SQL写法:
SELECT 1 FROM table WHERE a 1 AND b 2 LIMIT 1#### Java写法:
Integer exist xxDao.existXxxxByXxx(params);
if ( exist ! NULL ) {//当存在时执行这里的代码
} else {//当不存在时执行这里的代码
}根据查询条件查出来的条数越多性能提升的越明显在某些情况下还可以减少联合索引的创建。
in中值太多
对于批量查询接口我们通常会使用in关键字过滤出数据。比如想通过指定的一些id批量查询出用户信息。
sql语句如下
select id,name from category
where id in (1,2,3...100000000);如果我们不做任何限制该查询语句一次性可能会查询出非常多的数据很容易导致接口超时。
这时该怎么办呢
select id,name from category
where id in (1,2,3...100)
limit 500;可以在sql中对数据用limit做限制。
不过我们更多的是要在业务代码中加限制伪代码如下
public ListCategory getCategory(ListLong ids) {if(CollectionUtils.isEmpty(ids)) {return null;}if(ids.size() 500) {throw new BusinessException(一次最多允许查询500条记录)}return mapper.getCategoryList(ids);
}还有一个方案就是如果ids超过500条记录可以分批用多线程去查询数据。每批只查500条记录最后把查询到的数据汇总到一起返回。
不过这只是一个临时方案不适合于ids实在太多的场景。因为ids太多即使能快速查出数据但如果返回的数据量太大了网络传输也是非常消耗性能的接口性能始终好不到哪里去。
高效的分页
有时候列表页在查询数据时为了避免一次性返回过多的数据影响接口性能我们一般会对查询接口做分页处理。
在mysql中分页一般用的limit关键字
select id,name,age
from user limit 10,20;如果表中数据量少用limit关键字做分页没啥问题。但如果表中数据量很多用它就会出现性能问题。
比如现在分页参数变成了
select id,name,age
from user limit 1000000,20;mysql会查到1000020条数据然后丢弃前面的1000000条只查后面的20条数据这个是非常浪费资源的。
那么这种海量数据该怎么分页呢
优化sql
select id,name,age
from user where id 1000000 limit 20;先找到上次分页最大的id然后利用id上的索引查询。不过该方案要求id是连续的并且有序的。
还能使用between优化分页。
select id,name,age
from user where id between 1000000 and 1000020;需要注意的是between要在唯一索引上分页不然会出现每页大小不一致的问题。
用连接查询代替子查询
mysql中如果需要从两张以上的表中查询出数据的话一般有两种实现方式子查询 和 连接查询。
子查询的例子如下
select * from order
where user_id in (select id from user where status1)子查询语句可以通过in关键字实现一个查询语句的条件落在另一个select语句的查询结果中。程序先运行在嵌套在最内层的语句再运行外层的语句。
子查询语句的优点是简单结构化如果涉及的表数量不多的话。
但缺点是mysql执行子查询时需要创建临时表查询完毕后需要再删除这些临时表有一些额外的性能消耗。
这时可以改成连接查询。具体例子如下
select o.* from order o
inner join user u on o.user_id u.id
where u.status1join时要注意
我们在涉及到多张表联合查询的时候一般会使用join关键字。
而join使用最多的是left join和inner join。
left join求两个表的交集外加左表剩下的数据。
inner join求两个表交集的数据。
使用inner join的示例如下
select o.id,o.code,u.name
from order o
inner join user u on o.user_id u.id
where u.status1;如果两张表使用inner join关联mysql会自动选择两张表中的小表去驱动大表所以性能上不会有太大的问题。
使用left join的示例如下
select o.id,o.code,u.name
from order o
left join user u on o.user_id u.id
where u.status1;如果两张表使用left join关联mysql会默认用left join关键字左边的表去驱动它右边的表。如果左边的表数据很多时就会出现性能问题。
要特别注意的是在用left join关联查询时左边要用小表右边可以用大表。如果能用inner join的地方尽量少用left join。
提升group by的效率
我们有很多业务场景需要使用group by关键字它主要的功能是去重和分组。
通常它会跟having一起配合使用表示分组后再根据一定的条件过滤数据。
反例
select user_id,user_name from order
group by user_id
having user_id 200;这种写法性能不好它先把所有的订单根据用户id分组之后再去过滤用户id大于等于200的用户。
分组是一个相对耗时的操作为什么我们不先缩小数据的范围之后再分组呢
正例
select user_id,user_name from order
where user_id 200
group by user_id使用where条件在分组前就把多余的数据过滤掉了这样分组时效率就会更高一些。
其实这是一种思路不仅限于group by的优化。我们的sql语句在做一些耗时的操作之前应尽可能缩小数据范围这样能提升sql整体的性能。