设计一个关系型数据库(RDBMS)
1:程序实列
- 物理数据的存储管理。(尽可能的减少IO,一次性的读取所需要的所有数据)
- 缓存机制。
- SLQ解析。(慢sql日志;explain;)索引;锁模块。
- 日志管理(MongoDB)
- 权限划分(DBA来做的事情)
- 容灾机制
2:存储(文件系统)
1.1 索引
- 为什么使用索引?
- 让我们避免全表扫描去查找数据,从而提高检索效率。
- 什么样的信息能成为索引?
- 主键;唯一键;只要是能让数据具备一定区分性的字段。
-** 索引的数据结构?** - Mysql 最主要是B±Tree结构进行查找
- 主键;唯一键;只要是能让数据具备一定区分性的字段。
- 密集索引和悉数索引的区别?
- 密集索引文件中的每个搜索码都对应一个索引值;一个表中能创建一个密集索引。
- 稀疏素银文件中只为某些值建立索引值。
- 如何定位并优化慢查询sql?
- 根据慢日志定位慢查询日志。通过命令:show variables like ‘%quer%’;查询quer相关的配置变量(long_query_time;slow-query_long_file;slow_query_log;)
- 使用Explain;show profile 等工具分析sql。
- 属性type:system-const-eq_ref-ref-fulltext-ref_or_null-index_merge-unique_subquery-index_subquery-range-index-all;其中index;all都是全表扫描,需要优化sql;
- 属性extra,出现下面的两个也就表示咱们有可能需要优化了。:
- Using filesort:表示Musql会对结果使用一个外部索引排序,而不是从表里按索引次序读到相关内容。可能在内存或者磁盘上进行排序。Mysql中无法利用索引完成的排序操作称为“文件排序”。
- Using temporary:表示Mysql在对查询结果排序时使用临时表。常见于排序Order by 和 分组查询Group by;
- 修改sql或者尽量让sql走索引。
- 联合索引的最左匹配原则的成因?
- Mysql 创建符合索引排序的原则:首先会对复合索引的第一个索引字段进行排序,再对第二个字段进行排序。其实类似与Order By。
- 索引是建立得越多越好吗?不是,有以下三点。
- 数据量小的表不需要建立索引,建立索引会增加额外的索引开销。
- 数据表更需要维护索引,因此更多的索引意味着更多的维护成本。
- 更多的索引意味着也需要更多的空间。
1.2 锁
-
MyISAM与InnoDB关于锁方面的区别是什么
- MyISAM默认用的是表级锁,不支持行级锁。
- InnoDB默认用的是行级锁,也支持表级锁。
- InnoDB 当查询的时候不走索引的时候,用的是表级锁;反之则用的是行级锁。
- 共享锁和排他锁的兼容性
- 加了写锁时,无论你再加读锁还是写锁都需要等待写锁的释放才能执行。
- 加了读锁时,再加写锁则需要等待读锁的释放;而在家读锁是不影响的。
-
行级锁一定要比表级锁要好?
- 未必,锁的粒度越细,代价越高。相比表级锁之间在表的头不加锁来讲,表级锁还要扫描到某行的时候,对其上锁,代价甚大。InnoDB支持事务的同时,也相比MyISAM带来了更大的开销。InnoDB必须有且仅有一个聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引效率很高。但是辅助索引需要查询两次,先查到主键,然后再通过主键查询到数据。而MyISAM是非聚集索引,数据;文件是分离的,索引保存的是数据文件的指针,主键索引和辅助索引是独立的,因此MyISAM在纯检索系统中, 也就是增删改查很少的系统中,其性能要好于InnoDB。
-
MyISAM 适合的场景
- 适合频繁执行全表count语句,用一个变量保存了一个表的行数。
- 对数据进行增删查改的频率不高,查询非常频繁。因为增删会涉及到锁表操作。虽然可以通过一些配置让插入数据从表的尾部插入数据,但还是会产生很多的碎片。
- 没有事务的场景。
-
InnoDB 适合的场景
- 不保存数据的具体的行数,执行select count(1) 是需要重新扫描统计。
- 适合增删改查都相当频繁的系统,只是某些行被锁。
- 可靠行要求比较高,要求支持事务。
-
数据库锁的分类
- 按锁的粒度划分:表级锁;行级锁;页级锁。
- 按锁级别划分:功效所;排它锁。
- 按枷锁的方式划分:自动锁和显示锁。
- 自动锁:InnoDB的删改查,是InnoDB自动给我们加上的。
- 显示锁:for update; lock in share more mode。
- 按操作划分,可分为DML锁;DDL锁;对DB操作的锁(增删查改)就是DML锁,对表结构进行变更的就算DDL锁,如Alter table。
- 按使用方式划分可分为:乐观锁和悲观锁。 悲观锁其实就算DB的表锁,加锁会造成系统的负担且影响系统的并行性。乐观锁为一般数据不会造成冲突,所以在数据提交更新的时候,才会正式对数据的冲突与否进行检测。相对于悲观所,乐观锁并不会使用数据库提供的锁机制。
-
数据库事务(ACID)的四大特性
- 原子性(atomicity):整个事务中的所有操作要么全部提交成功,要么全部失败回滚。
- 一致性(consistency):数据库总是从一个一致性的状态转换到另外一个一致性的状态。比如说整个数据库重点所有操作都是一次性全部提交,所以事务中所做的修改不会保存到数据库中去。
- 隔离性(isolation)【通常来说】,一个事务所作的所有修改操作在提交以前,对其它事物都是不可见的。
- 未提交读(read-uncommitted-脏读):事务中的修改,即使事务没有提交,对其它的事务也都是可见的。换句 话说,也就是事务可读取未提交的数据。注意,这个级别会导致很多问题,慎用!
- 提交读(read-committed-不可重复读):大部分数据库系统的默认隔离级别(mysql不是)。简而言之,一个事务开始时,只能“看见”已经提交的事务所作的修改。存在两次查询,可能查询出不一样的结果。比如说:事务T1读取一行记录后,事务T2修改了此条记录,则事务T1再次读取得到的是事务T2修改后的结果。
- 可重复读(repeatable-read-幻读):(InnoDBl默认级别)该级别解决了脏读的问题。保证了在同一个事务中多次读取同样的记录的结果是一致的。但是理论上,此隔离级别还是无法解决另外一个幻读的问题。所谓幻读,就是当事务T1读取某个范围内的数据后,事务T2在此范围内新增了一条数据,则事务T1再次读取此范围的数据时,会产生幻行。
- 可串行化(serializable):是最高的隔离级别。通过强制事务串行执行,避免了幻读问题。简单来说,可串行化会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。实际应用中也很少用到这个隔离级别,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑该级别。
持久性:一旦事务提交,则其所作的所有修改操作都将永久保存到数据库中。
- 持久性(durability)
-
当前读和快照读
- 当前读:不管你上的是共享锁还是排他锁都是当前读。因为它读取的是记录的最新版本,并且读取之后还得保证其它事务不能影响到当前的事务。示例:select…lock in share mode;for update;update;delete;insert;
- 快照读:不加锁的非阻塞读,可能读到的数据可能是历史版本并不是最新的数据。
-
InnoDB可重复读隔离级别下如何避免幻读
- 表象:快照读(非阻塞读)–伪MVCC
- 内在:next-key锁(行锁+grp锁)
-
next-key锁(行锁+Gap锁)
- 行锁
- gap锁(间隙锁):锁定一个范围,但不包括记录本身。目的是为了防止同一事物的两次当前读,避免幻读的情况。在RC及其隔离级别更低的事务中是不存在的,这也是RC及更低事务无法避免幻读的原因。
-
InnoDB加Gap锁的场景
- 如果where条件全部命中(精确查询),则不会用Gap锁,只会加记录锁。
- 如果where 条件部分命中或者全不命中,则会加Gap锁。
- 非唯一索引的当前读
- 不走索引的当前读,相比表锁,间隙锁的代价更高。
-
RC;RR级别下的InnoDB的非阻塞读如何实现
- 数据行里的DB_TRX_ID(事务ID);DB_ROLL_RTR(回滚指针);DB_ROW_ID(行号)字段;
- undo 日志(存储的是老版数据,主要用于事务回滚;快照读)。
- read view;