面试经典题——数据库
1、数据库索引
- 索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。如果想按特定职员的姓来查找他或她,则与在表中搜索所有的行相比,索引有助于更快地获取信息
- 索引的一个主要目的就是加快检索表中数据的方法,亦即能协助信息搜索者尽快的找到符合限制条件的记录ID的辅助数据结构
2、数据库事务
- 数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理
3、inner join和left join
- left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录
- right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录
- inner join(等值连接) 只返回两个表中联结字段相等的行
4、数据库的ACID特性
- 原子性:事务被视为不可分割的最小单元,事物的所有操作要不成功,要不失败回滚,而回滚可以通过日志来实现,日志记录着事务所执行的修改操作,在回滚时反向执行这些修改操作。
- 一致性:数据库在事务执行前后都保持一致性状态,在一致性状态下,所有事务对一个数据的读取结果都是相同的。
- 隔离性:一个事务所做的修改在最终提交以前,对其他事务是可不见的。
- 持久性:一旦事务提交,则其所做的修改将会永远保存到数据库中。
5、数据库的三大范式
- 第一范式:当关系模式R的所有属性都不能再分解为更基本的数据单位时,称R是满足第一范式,即属性不可分
- 第二范式:如果关系模式R满足第一范式,并且R得所有非主属性都完全依赖于R的每一个候选关键属性,称R满足第二范式
- 第三范式:设R是一个满足第一范式条件的关系模式,X是R的任意属性集,如果X非传递依赖于R的任意一个候选关键字,称R满足第三范式,即非主属性不传递依赖于键码
-
(1)简单归纳:第一范式(1NF):字段不可分; 第二范式(2NF):有主键,非主键字段依赖主键; 第三范式(3NF):非主键字段不能相互依赖。
(2)解释:1NF:原子性。 字段不可再分,否则就不是关系数据库;; 2NF:唯一性 。一个表只说明一个事物; 3NF:每列都与主键有直接关系,不存在传递依赖。
6、mysql的MVCC机制
- MVCC是一种多版本并发控制机制,是MySQL的InnoDB存储引擎实现隔离级别的一种具体方式,用于实现提交读和可重复读这两种隔离级别。MVCC是通过保存数据在某个时间点的快照来实现该机制,其在每行记录后面保存两个隐藏的列,分别保存这个行的创建版本号和删除版本号,然后Innodb的MVCC使用到的快照存储在Undo日志中,该日志通过回滚指针把一个数据行所有快照连接起来。
7、SQL优化方法有哪些
- 在经常性的检索列上,建立必要索引,以加快搜索速率,避免全表扫描(索引覆盖扫描);
- 多次查询同样的数据,可以考虑缓存该组数据;
- 审视select * form tables, 你需要所有列数据吗?
- 切分查询(大查询切分成为小查询,避免一次性锁住大量数据)
- 分解关联查询(单表查询,结果在应用程序中进行关联,可以减少处理过程中的锁争用)
- 尽量先做单表查询;
8、MySQL 4 种隔离级别
- 未提交读READ UNCOMMITTED:一个事务在提交之前,对其他事务是可见的,即事务可以读取未提交的数据。存在“脏读”(读到了脏数据)问题;
- 提交读READ COMMITTED:事务在提交之前,对其它事务是不可见的。存在“不可重复读”(两次查询的得到的结果可能不同,即可能在查询的间隙,有事务提交了修改)问题。解决了“脏读”问题。
- 可重复读REPEATABLE READ:在同一事务中多次读取的数据是一致的。解决了脏读和不可重复读问题,存在“幻读”(在事务两次查询间隙,有其他事务又插入或删除了新的记录)。--- MySQL默认隔离级别。
- 可串行化SERIALIZABLE:强制事务串行化执行。即一个事物一个事物挨个来执行,可以解决上述所有问题
9、锁及粒度:
- 共享锁/读锁:互不阻塞,优先级低
- 排他锁/写锁:阻塞其他锁,优先级高,即确保在一个事务写入时不受其他事务的影响。
- 锁粒度:锁定的数据量越少(粒度越小),并发程度越高,但相应的加锁、检测锁、释放锁用的系统开销也随之增大。
- 锁策略:锁开销与数据安全性之间的平衡
- 表锁:锁住整张表,读锁互不阻塞,写锁阻塞其他所有读写锁(同一张表)。开销最小。
- 行级锁:对每一行数据(记录)加锁,开销大,并发程度高。
10、InnoDB对死锁的处理
- 此处死锁与OS死锁类似,多个事务互相持有对方所有要申请资源的锁不释放,造成环路死锁。MySQL InnoDB引擎检测到死锁循环依赖后,回滚持有最少行级锁的事务
11、MySQL存储引擎简介
- InnoDB,最为通用/推荐的一种引擎,支持事务、行级锁、甚至间隙锁(避免幻读)、支持热备份,MVCC,在并发上占优势,系统资源占用多。
- MyISAM,默认的存储引擎,不支持事务和行级锁,只支持表锁,某些场景性能很好:占用存储上优,查询速度上完胜(大概是InnoDB的3倍)系统资源占用少。
- InnoDB支持事务, MyISAM不支持;
- InnoDB支持行级锁、表锁;MyISAM只支持表锁;
- InnoDB支持MVCC,MyISAM不支持;
- InnoDB不支持全文索引,MyISAM支持;
- InnoDB支持外键,MyISAM不支持外键;
- InnoDB和MyISAM都支持B+树索引,InnoDB还支持自适应哈希索引
- MyISAM实现了前缀压缩技术,占用存储空间更小(但会影响查找),InnoDB是原始数据存储,占用存储更大。
12、
Redis常见数据结构以及使用场景
- String数据结构是简单的key-value类型,value其实不仅可以是String,也可以是数字。 常规key-value缓存应用; 常规计数:微博数,粉丝数等。
- Hash是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象,后续操作的时候,你可以直接仅 仅修改这个对象中的某个字段的值。 比如我们可以Hash数据结构来存储用户信息,商品信息等。
- List就是链表,Redis list 的应用场景非常多,也是Redis最重要的数据结构之一,比如微博的关注列表,粉丝列表, 消息列表等功能都可以用Redis的 list 结构来实现。Redis list 的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销。另外可以通过 lrange 命令,就是从某个元素开始读取多少个元素,可以基于 list 实现分页查询,这个很棒的一个功 能,基于 Redis 实现简单的高性能分页,可以做类似微博那种下拉不断分页的东西(一页一页的往下走),性能高。
- Set对外提供的功能与list类似是一个列表的功能,特殊之处在于 set 是可以自动排重的。当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在 一个set集合内的重要接口,这个也是list所不能提供的。可以基于 set 轻易实现交集、并集、差集的操作。
- Sorted Set:和set相比,sorted set增加了一个权重参数score,使得集合中的元素能够按score进行有序排列。
13、有Redis相对MySQL有点
- 高性能:假如用户第一次访问数据库中的某些数据。这个过程会比较慢,因为是从硬盘上读取的。将该用户访问的数据存在缓存中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据即可!
- 高并发:直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。
14、C++中的Map也是一种缓存型数据结构,为什么不用Map,而选择Redis做缓存?
- 严格意义上来说缓存分为本地缓存和分布式缓存。
- 那以 C++ 语言为例,我们可以使用 STL 下自带的容器 map 来实现缓存,但只能实现本地缓存,它最主要的特点是轻量以及快速,但是其生命周期随着程序的销毁而结束,并且在多实例的情况下,每个实例都需要各自保存一份缓存,缓存不具有一致性。使用 Redis 或 Memcached 之类的称为分布式缓存,在多实例的情况下,各实例共享一份缓存数据,缓存具有一致性。这是Redis或者Memcached的优点所在,但它也有缺点,那就是需要保持 Redis 或 Memcached服务的高可用,整个程序架构上较为复杂。
15、Redis优点
- 访问速度快,因为数据存在内存中,类似于Java中的HashMap或者C++中的哈希表(如unordered_map/unordered_set),这两者的优势就是查找和操作的时间复杂度都是O(1)
- 数据类型丰富,支持String,list,set,sorted set,hash这五种数据结构
- 支持事务,Redis中的操作都是原子性,换句话说就是对数据的更改要么全部执行,要么全部不执行,这就是原子性的定义
- 特性丰富:Redis可用于缓存,消息,按key设置过期时间,过期后将会自动删除。
16、缓存中常说的热点数据和冷数据是什么?
- 热数据就是访问次数较多的数据
- 冷数据就是访问很少或者从不访问的数据
17、Redis为单线程,为什么这么快
- Redis的全部操作都是纯内存的操作;
- Redis采用单线程,有效避免了频繁的上下文切换;
- 采用了非阻塞I/O多路复用机制
18、Redis设置过期时间的两种方案
- 定期删除:Redis默认是每隔 100ms 就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删 除。注意这里是随机抽取的。为什么要随机呢?你想一想假如 Redis 存了几十万个 key ,每隔100ms就遍历所 有的设置过期时间的 key 的话,就会给 CPU 带来很大的负载!
- 惰性删除 :定期删除可能会导致很多过期 key 到了时间并没有被删除掉。所以就有了惰性删除。它是指某个键值过期后,此键值不会马上被删除,而是等到下次被使用的时候,才会被检查到过期,此时才能得到删除,惰性删除的缺点很明显是浪费内存。 除非你的系统去查一下那个 key,才会被Redis给删除掉。这就是所谓的惰性删除!
19、缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存击穿、缓存降级
- 缓存雪崩:
- 指的是缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
- 解决办法
- 事前:尽量保证整个 Redis 集群的高可用性,发现机器宕机尽快补上,选择合适的内存淘汰策略。
- 事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL崩掉, 通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
- 事后:利用 Redis 持久化机制保存的数据尽快恢复缓存
- 缓存穿透
- 一般是黑客故意去请求缓存中不存在的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量 请求而崩掉。
- 解决办法
- 布隆过滤器
- 这是最常见的一种解决方法了,它是将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压 力。对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力;
- 缓存空对象
- 当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源;如果一个查询返回的数据为空(不管是数据不存 在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。
- 缓存预热
- 缓存预热是指系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题。用户会直接查询事先被预热的缓存数据
- 缓存更新
- 除了缓存服务器自带的缓存失效策略之外(Redis默认的有6中策略可供选择),我们还可以根据具体的业务需求进行自定义的缓存淘汰,常见的策略有两种: (1)定时去清理过期的缓存;定时删除和惰性删除 (2)当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存。 两者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的,第二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂!具体用哪种方案,大家可以根据自己的应用场景来权衡。
- 缓存击穿
- 缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
- 缓存降级
- 当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。 降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购物车、结算)。服务降级的目的,是为了防止Redis服务故障,导致数据库跟着一起发生雪崩问题。因此,对于不重要的缓存数据,可以采取服务降级策略,例如一个比较常见的做法就是,Redis出现问题,不去数据库查询,而是直接返回默认值给用户。
20、Redis集群,集群原理
- Redis Sentinel(哨兵)着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。
- Sentinel(哨兵)可以监听集群中的服务器,并在主服务器进入下线状态时,自动从服务器中选举出新的主服务器。
- Redis Cluster(集群)着眼于扩展性,在单个Redis内存不足时,使用Cluster进行分片存储。
21、如何解决Redis并发竞争Key问题
- 分布式锁(zookeeper 和 Redis 都可以实现分布式锁)
22、数据库优化方案
- 缓存双淘汰法
- 先淘汰缓存
- 再写数据库
- 往消息总线esb发送一个淘汰消息,发送立即返回。写请求的处理时间几乎没有增加,这个方法淘汰了缓存两次。因此被称为“缓存双淘汰法“,而在消息总线下游,有一个异步淘汰缓存的消费者,在拿到淘汰消息在1s后淘汰缓存,这样,即使在一秒内有脏数据入缓存,也能够被淘汰掉。
- 异步淘汰缓存
23、关系型和非关系型数据库
- 关系型数据库的优点
- 容易理解。因为它采用了关系模型来组织数据。
- 可以保持数据的一致性。
- 数据更新的开销比较小。
- 支持复杂查询(带where子句的查询)
- 非关系型数据库的优点
- 不需要经过SQL层的解析,读写效率高。
- 基于键值对,数据的扩展性很好。
- 可以支持多种类型数据的存储,如图片,文档等等
24、MySQL执行一条sql的步骤
- 连接器:管理连接、权限验证;
- 查询缓存:命中缓存则直接返回结果;
- 分析器:对SQL进行词法分析、语法分析;(判断查询的SQL字段是否存在也是在这步)
- 优化器:执行计划生成、选择索引;
- 执行器:操作引擎、返回结果;
- 存储引擎:存储数据、提供读写接口
25、数据库隔离级别
- 未提交读,事务中发生了修改,即使没有提交,其他事务也是可见的,比如对于一个数A原来50修改为100,但是我还没有提交修改,另一个事务看到这个修改,而这个时候原事务发生了回滚,这时候A还是50,但是另一个事务看到的A是100.可能会导致脏读、幻读或不可重复读
- 提交读,对于一个事务从开始直到提交之前,所做的任何修改是其他事务不可见的,举例就是对于一个数A原来是50,然后提交修改成100,这个时候另一个事务在A提交修改之前,读取的A是50,刚读取完,A就被修改成100,这个时候另一个事务再进行读取发现A就突然变成100了;可以阻止脏读,但是幻读或不可重复读仍有可能发生
- 重复读,就是对一个记录读取多次的记录是相同的,比如对于一个数A读取的话一直是A,前后两次读取的A是一致的;可以阻止脏读和不可重复读,但幻读仍有可能发生
- 可串行化读,在并发情况下,和串行化的读取的结果是一致的,没有什么不同,比如不会发生脏读和幻读;该级别可以防止脏读、不可重复读以及幻读
26、数据库并发事务带来的问题
- 脏读:在第一个修改事务和读取事务进行的时候,读取事务读到的数据为100,这是修改之后的数据,但是之后该事务满足一致性等特性而做了回滚操作,那么读取事务得到的结果就是脏数据了。
- 幻读:一般是T1在某个范围内进行修改操作(增加或者删除),而T2读取该范围导致读到的数据是修改之间的了,强调范围。
- 丢弃修改:两个写事务T1 T2同时对A=0进行递增操作,结果T2覆盖T1,导致最终结果是1 而不是2,事务被覆盖
- 不可重复读:T2 读取一个数据,然后T1 对该数据做了修改。如果 T2 再次读取这个数据,此时读取的结果和第一次读取的结果不同。
27、数据库悲观锁和乐观锁原理
- 悲观锁,先获取锁,再进行业务操作,一般就是利用类似 SELECT … FOR UPDATE 这样的语句,对数据加锁,避免其他事务意外修改数据。 当数据库执行SELECT … FOR UPDATE时会获取被select中的数据行的行锁,select for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。
- 乐观锁,先进行业务操作,只在最后实际更新数据时进行检查数据是否被更新过。Java 并发包中的 AtomicFieldUpdater 类似,也是利用 CAS 机制,并不会对数据加锁,而是通过对比数据的时间戳或者版本号,来实现乐观锁需要的版本判断。
28、MySQL索引主要使用的两种数据结构
-
哈希索引,对于哈希索引来说,底层的数据结构肯定是哈希表,因此在绝大多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;其余大部分场景,建议选择BTree索引
-
BTree索引,Mysql的BTree索引使用的是B树中的B+Tree,BTREE索引就是一种将索引值按一定的算法,存入一个树形的数据结构中(二叉树),每次查询都是从树的入口root开始,依次遍历node,获取leaf。
但对于主要的两种存储引擎(MyISAM和InnoDB)的实现方式是不同的。
29、MySQL中四种索引类型
- FULLTEXT :即为全文索引,目前只有MyISAM引擎支持。其可以在CREATE TABLE ,ALTER TABLE ,CREATE INDEX 使用,不过目前只有 CHAR、VARCHAR ,TEXT 列上可以创建全文索引。
- HASH :由于HASH的唯一(几乎100%%的唯一)及类似键值对的形式,很适合作为索引。 HASH索引可以一次定位,不需要像树形索引那样逐层查找,因此具有极高的效率。但是,这种高效是有条件的,即只在“=”和“in”条件下高效,对于范围查询、排序及组合索引仍然效率不高。
- BTREE :BTREE索引就是一种将索引值按一定的算法,存入一个树形的数据结构中(二叉树),每次查询都是从树的入口root开始,依次遍历node,获取leaf。这是MySQL里默认和最常用的索引类型。
- RTREE :RTREE在MySQL很少使用,仅支持geometry数据类型,支持该类型的存储引擎只有MyISAM、BDb、InnoDb、NDb、Archive几种。 相对于BTREE,RTREE的优势在于范围查找。
30、什么时候需要创建数据库索引
- 在最频繁使用的、用以缩小查询范围的字段,需要排序的字段上建立索引。
- 不宜: 1)对于查询中很少涉及的列或者重复值比较多的列 2)对于一些特殊的数据类型,不宜建立索引,比如文本字段(text)等。
31、覆盖索引是什么
- 如果一个索=引包含(或者说覆盖)所有需要查询的字段的值,我们就称 之为“覆盖索引”
32、数据库中主键、超键、候选键、外键
-
超键:在关系中能唯一标识元组的属性集称为关系模式的超键
-
候选键:不含有多余属性的超键称为候选键。也就是在候选键中,若再删除属性,就不是键了!
-
主键:用户选作元组标识的一个候选键程序主键
-
外键:如果关系模式R中属性K是其它模式的主键,那么k在模式R中称为外键。
33、MySQL常见的存储引擎InnoDB、MyLSAM区别,使用场景
- 1)事务:MyISAM不支持,InnoDB支持 2)锁级别: MyISAM 表级锁,InnoDB 行级锁及外键约束 3)MyISAM存储表的总行数;InnoDB不存储总行数; 4)MyISAM采用非聚集索引,B+树叶子存储指向数据文件的指针。InnoDB主键索引采用聚集索引,B+树叶子存储数据
- 适用场景: MyISAM适合: 插入不频繁,查询非常频繁,如果执行大量的SELECT,MyISAM是更好的选择, 没有事务。 InnoDB适合: 可靠性要求比较高,或者要求事务; 表更新和查询都相当的频繁, 大量的INSERT或UPDATE
34、聚合索引和非聚合索引区别
- 非聚集索引和聚集索引的区别在于, 通过聚集索引可以查到需要查找的数据, 而通过非聚集索引可以查到记录对应的主键值 , 再使用主键的值通过聚集索引查找到需要的数据。 聚集索引和非聚集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致。
- 聚集索引(Innodb)的叶节点就是数据节点,而非聚集索引(MyisAM)的叶节点仍然是索引节点,只不过其包含一个指向对应数据块的指针。
35、MySQL中CHAR和VARCHAR区别
- char的长度是不可变的,用空格填充到指定长度大小,而varchar的长度是可变的。
- char的存取数度还是要比varchar要快得多
- char的存储方式是:对英文字符(ASCII)占用1个字节,对一个汉字占用两个字节。varchar的存储方式是:对每个英文字符占用2个字节,汉字也占用2个字节。
36、MySQL中有哪些索引
- 普通索引:仅加速查询
- 唯一索引:加速查询 + 列值唯一(可以有null)
- 主键索引:加速查询 + 列值唯一(不可以有null)+ 表中只有一个
- 组合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并
- 全文索引:对文本的内容进行分词,进行搜索
- 索引合并:使用多个单列索引组合搜索
- 覆盖索引:select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖
- 聚簇索引:表数据是和主键一起存储的,主键索引的叶结点存储行数据(包含了主键值),二级索引的叶结点存储行的主键值。使用的是B+树作为索引的存储结构,非叶子节点都是索引关键字,但非叶子节点中的关键字中不存储对应记录的具体内容或内容地址。叶子节点上的数据是主键与具体记录(数据内容)
37、MySQL索引使用注意事项
- 不要在列上使用函数,这将导致索引失效而进行全表扫描
- 尽量避免使用 != 或 not in或 <> 等否定操作符
- 多个单列索引并不是最佳选择
- 复合索引的最左前缀原则
- 覆盖索引的好处
- 范围查询对多列查询的影响
- 索引不会包含有NULL值的列
- 隐式转换的影响
38、数据库表锁和行锁
表锁
不会出现死锁,发生锁冲突几率高,并发低。
MyISAM在执行查询语句(select)前,会自动给涉及的所有表加读锁,在执行增删改操作前,会自动给涉及的表加写锁。
MySQL的表级锁有两种模式:表共享读锁和表独占写锁。
读锁会阻塞写,写锁会阻塞读和写
- 对MyISAM表的读操作,不会阻塞其它进程对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,才会执行其它进程的写操作。
- 对MyISAM表的写操作,会阻塞其它进程对同一表的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作。
MyISAM不适合做写为主表的引擎,因为写锁后,其它线程不能做任何操作,大量的更新会使查询很难得到锁,从而造成永远阻塞。
行锁
会出现死锁,发生锁冲突几率低,并发高。
在MySQL的InnoDB引擎支持行锁,与Oracle不同,MySQL的行锁是通过索引加载的,也就是说,行锁是加在索引响应的行上的,要是对应的SQL语句没有走索引,则会全表扫描,行锁则无法实现,取而代之的是表锁,此时其它事务无法对当前表进行更新或插入操作。
行锁的实现需要注意:
- 行锁必须有索引才能实现,否则会自动锁全表,那么就不是行锁了。
- 两个事务不能锁同一个索引。
- insert,delete,update在事务中都会自动默认加上排它锁。
39、SQL语法中内连接、外连接、自连接、交叉连接
- 内连接:只有两个元素表相匹配的才能在结果集中显示。
- 外连接: 左外连接: 左边为驱动表,驱动表的数据全部显示,匹配表的不匹配的不会显示。 右外连接:右边为驱动表,驱动表的数据全部显示,匹配表的不匹配的不会显示。
- 全外连接:连接的表中不匹配的数据全部会显示出来。
- 交叉连接: 笛卡尔效应,显示的结果是链接表数的乘积。
40、数据库结构优化
- 范式优化: 比如消除冗余(节省空间。。)
- 反范式优化:比如适当加冗余等(减少join)
- 限定数据的范围: 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内。
- 读/写分离: 经典的数据库拆分方案,主库负责写,从库负责读;
- 拆分表:分区将数据在物理上分隔开,不同分区的数据可以制定保存在处于不同磁盘上的数据文件里。这样,当对这个表进行查询时,只需要在表分区中进行扫描,而不必进行全表扫描,明显缩短了查询时间,另外处于不同磁盘的分区也将对这个表的数据传输分散在不同的磁盘I/O,一个精心设置的分区可以将数据传输对磁盘I/O竞争均匀地分散开。对数据量大的时时表可采取此方法。可按月自动建表分区。
41、数据库如何保证一致性
- 从数据库层面,数据库通过原子性、隔离性、持久性来保证一致性。也就是说ACID四大特性之中,C(一致性)是目的,A(原子性)、I(隔离性)、D(持久性)是手段,是为了保证一致性,数据库提供的手段。数据库必须要实现AID三大特性,才有可能实现一致性。例如,原子性无法保证,显然一致性也无法保证。
- 从应用层面,通过代码判断数据库数据是否有效,然后决定回滚还是提交数据