目录
1、数据库的三大范式是什么?
1.1、每列字段保持原子性(字段不可再拆,字段不可以是:“王二_13823456789”)
1.2、确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)
1.3、确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
2、mysql索引
2.1 索引定义:
2.2 优缺点:
优点:
缺点:
2.3 B+树示意图
2.4 B树和B+树的区别
2.4.1 非叶子节点不存储data,只存储索引,可以放更多的索引。
2.4.2 叶子节点包含了所有的索引字段。
2.4.3 叶子节点用指针链接,提高了区间访问性能。
2.5 mysql存储能力的预估
2.6 mysql数据库数据的存储位置
2.7 innodb 和 myisam 的区别
2.7.1 innodb表数据文件本身就是按照B+树组织的一个索引结构文件
2.7.2 聚集索引叶子节点包含了完整的数据记录
2.8 为什么建议Innodb表必须建立主键,并且推荐使用整型自增的主键?
2.8.1、mysql会先找一个唯一列建立主键,如果找不到,mysql会增加一个隐藏列。为了节省mysql资源,要自己建立主键。
2.8.2、用整形的原因是查找过程中比大小速度很快。
2.8.3、自增的原因是建立索引的过程很快。如果从中间插入会有叶子节点分裂平衡的过程。
2.9 聚集索引和非聚集索引和哈希索引
2.10 为什么非主键索引叶子节点存主键
2.11 联合索引
2.12 索引优化
2.13 索引设计原则
1、代码先行,索引后上
2、联合索引尽量覆盖条件
3、不要在小基数字段上建立索引
4、长字符串我们可以采用前缀索引
5、where与order by 冲突时候有限where
3.Explain 详解与索引
3.1 explain 的字段:
3.1.1 select_type
3.1.2 table:
3.1.4 type:
3.1.5 key:用到的索引的名字
3.1.6 key_len:索引占用的不同字节数,不用太在乎
4、SQL底层执行原理详解
5、深入理解mysql事务隔离级别
5.1 事务以及ACID
原子性(Atomicity):
一致性(Consistent):
隔离性(Isolation):
持久性(Durable):
5.2 并发事务带来的问题
更新丢失(Lost Update)或脏写
脏读(Dirty Reads)
不可重复度(Non-Repeatable Reads)
幻读(Phantom Reads)
5.3 事务的隔离级别
5.3.1、第一种隔离级别:Read uncommitted(读未提交)
5.3.2、第二种隔离级别:Read committed(读提交)
5.3.3、第三种隔离级别:Repeatable read(可重复读取)
5.3.4、第四种隔离级别:Serializable(可序化)
6.锁详解
6.1 从性能上分乐观锁(用版本对比来实现)和悲观锁
6.1.1 乐观锁的概念:
6.1.2 悲观锁的概念
6.1.3 乐观锁的实现方式:
6.1.4 悲观锁的实现方式:
6.2 从对数据库操作的类型分,分为读锁和写锁(都是悲观锁)
6.2.2 写锁(排他锁,X锁(eXclusive)):
6.3 从对数据操作的颗粒度分,分为表锁和行锁
表锁
行锁
间隙锁
临键锁
6.4 如何处理死锁
7.MVCC多版本并发控制机制
指数据库表的设计规范:三大范式示例
索引是一种优化查询的数据结构,是表的一部分,可以理解为一本书的目录
1、大大加快数据的检索速度;
2、创建唯一性索引,保证数据库表中每一行数据的唯一性;
3、加速表和表之间的连接;
4、在使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间
1、索引需要占物理空间。
2、当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度。
默认每页16kb
show global status like 'Innodb_page_size'
查询结果
Variable_name Value
Innodb_page_size 16384
一页大约可以放1170 个元素
1170*1170*16 = 2千万左右,高度只有三(1170是因为B+树只存索引,能放更多索引以减少高度)
data目录下,库是文件夹名,文件夹名下面是若干表名(Innodb 一个表对应两个文件 frm 表结构 ibd 索引和数据,myisam一个对应三个文件frm、MYD 数据文件 、MYI 索引文件)
索引和数据放在一起的是聚集索引,innodb
否则是非聚集索引 myisam
哈希索引算法和哈希map类似,很多时候查询的速度更高,因为只需要一次哈希就可以了,哈希索引只合适用 IN = 不支持范围查询 所以绝大多数情况下不用哈希索引
为了一致性和节省存储空间
一张表不推荐建立太多的单值索引。能建立联合索引尽量建立联合索引,尽量大多数查询场景能用联合索引搞定。最左前缀原理。
1、
select * from table force index(index) where
强制使用索引。(强制使用索引不一定就变快了)
2、一样的表,数据量不一样,也不一定走不走索引。cost机制算出来的。
3、范围查询联合索引建立在最后比如 age
4、一张表可以建立两到三个联合索引,建立太多影响增删改。
5、如果 七日内登录和年龄都要筛选,都是范围查询怎么办。写个程序给七日内登录打一个 1 的标记。再在这个基础上如果还有身高+年龄这种范围筛选怎么办,再建立一个联合索引。
6、mysql的资源非常宝贵,尽量单表查询,级联查询尽量再java中解决。大厂 90% 以上单表。不然压力在mysql上且难以优化。
等到主体业务功能开发完毕,把涉及到的相关sql拿出来再建立索引。
满足最左前缀原则
比如性别:男,女 基数就是2
可以神对字段的前20个字符建立索引
key index(name(20),age,position)
explain select * from film where id = ?
simple:普通查询
primary:复杂查询中最外层的select
subquery:包含在select中的子查询
derived:包含在from子句中的子查询
表名,如果是衍生表,会有类似
3.1.3 id:值越大优先级越高
从最优到最差分别为
NULL(很少有这种情况的sql)
system:比const效率更高,const的特殊形式,比如一张表只有一条记录
const:类似查询主键或者唯一索引
eq_ref:关联的时候用主键关联
ref:走了索引,不过不是唯一索引,普通索引或者联合主键的前缀查询等
range:用了索引,不过用的是范围查找,比如
index:一般情况下扫描二级索引,达到查询结果(因为二级索引不是聚簇索引会小很多),效率不高要规避
ALL:全表扫描,其实扫描的是主键(聚簇)索引
优化保证到range级别,最好达到ref
4.1、mysql中有张user表,连接器在连接时会在该表校验host,user,pwd。等权限。获取了权限后是一个长连接,在连接的生命周期没有结束时候,更高权限修改了该账号的权限,对当前连接中的用户的权限是不生效的。长连接的超时时间是8小时。
4.2、show processlist; 看见各个客户端的信息以及正在干什么。
4.3、mysql5.7以及以前有一个缓存机制,非常鸡肋,8以后干掉了。innodb的引擎层中自己也会有缓存。
4.4、词法分析器:校验合法性,拆成语法树。对逆向操作也有用处(如rollback )。
4.5、bin-log 归档记录的语句日志(二进制的方式记录),删库恢复
4.5.1、my.cnf 配置文件开启bin-log
log-bin=目录
binlog-format=ROW
sync-binlog=1
4.5.2、binlog 有三种格式,
statement 记录逻辑,产生结果的过程
row 记录update语句执行的结果,产生的结果 √
mixed 是两种方式的综合
4.5.3、恢复的时候根据点位(position)恢复。也可以按照文件全量恢复和按照时间恢复。
事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。操作层面要么都成功要么都失败。
在事务开始和完成时,数据都必须保持一致状态。比如银行转账。数据层面都一致。
数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的独立环境中执行。
事务完成后,修改时永久的,即便出现系统故障也能保持。
多个事务访问同一行,每个事务不知道其他事务存在,就会发生最后的更新覆盖了其他事务所作的更新的情况。
事务A读到了事务B已经修改但还未提交的数据。依据这个未提交的数据来进行操作会有问题。
一个事务读取一个数据后,再次读取该数据,发现这个数据已经改变了。
事务A读到了事务B提交的新增的数据。
如果一个事务已经开始写数据,则另外一个事务不允许同时进行写操作,但允许其他事务读此行数据,该隔离级别可以通过“排他写锁”,但是不排斥读线程实现。这样就避免了更新丢失,却可能出现脏读,也就是说事务B读取到了事务A未提交的数据。
解决了更新丢失,但还是可能会出现脏读。
如果是一个读事务(线程),则允许其他事务读写,如果是写事务将会禁止其他事务访问该行数据,该隔离级别避免了脏读,但是可能出现不可重复读。事务A事先读取了数据,事务B紧接着更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。
解决了更新丢失和脏读问题。
可重复读取是指在一个事务内,多次读同一个数据,在这个事务还没结束时,其他事务不能访问该数据,这样就可以在同一个事务内两次读到的数据是一样的,因此称为是可重复读隔离级别,读取数据的事务将会禁止写事务,写事务则禁止任何其他事务,这样避免了不可重复读和脏读,但是有时可能会出现幻读。
读取数据的事务可以通过“共享读镜”和“排他写锁”实现。
解决了更新丢失、脏读、不可重复读、但是还会出现幻读。
提供严格的事务隔离,它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行,如果仅仅通过“行级锁”是无法实现序列化的,必须通过其他机制保证新插入的数据不会被执行查询操作的事务访问到。
序列化是最高的事务隔离级别,同时代价也是最高的,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻读。
查询数据库的隔离级别的sql语句
show variables like 'tx_isolation' 一般都是可重复读
乐观锁:指的是在操作数据的时候非常乐观,乐观地认为别人不会同时修改数据,因此乐观锁默认是不会上锁的,只有在执行更新的时候才会去判断在此期间别人是否修改了数据,如果别人修改了数据则放弃操作,否则执行操作。
悲观锁:指的是在操作数据的时候比较悲观,悲观地认为别人一定会同时修改数据,因此悲观锁在操作数据时是直接把数据上锁,直到操作完成之后才会释放锁,在上锁期间其他人不能操作数据。
读取频繁使用乐观锁,写入频繁使用悲观锁。
CAS机制
版本号机制:
版本号机制的基本思路,是在数据中增加一个version字段用来表示该数据的版本号,每当数据被修改版本号就会加1。当某个线程查询数据的时候,会将该数据的版本号一起读取出来,之后在该线程需要更新该数据的时候,就将之前读取的版本号与当前版本号进行比较,如果一致,则执行操作,如果不一致,则放弃操作。
悲观锁的实现方式也就是加锁,加锁既可以在代码层面(比如Java中的synchronized关键字),也可以在数据库层面(比如MySQL中的排他锁)。
多个操作读操作可以同时进行再同一份数据上
当前写操作没有完成前,它会阻塞其他写锁和读锁
手动增加表锁
lock table 表名称 read(write),表名2 read(write)
查看表上加过的锁
show open tables
删除表锁
unlock tables
InnoDB 支持事务,支持行级锁
总结:
myisam 会根据sql语句的读写给表加读写锁。
innodb select 时候因为有mvcc机制不会加锁。增删改的时候会加行锁。
1. 出现原因:A用户问A资源锁住A时请求B资源,B用户问B资源锁住B时请求A资源,产生死锁。
用Use SHOW INNODB STATUS来确定最后一个死锁的原因。
经常提交你的事务。
无索引行锁会升级为表锁
锁主要加在索引上,如果对非索引字段进行更新记录,可能会升级为表锁。
innoDB的行锁是针对索引加的锁,不是针对记录加的锁。
MVCC(Multi-Version Concurrency Control)
只在 读已提交 和 可重复度 这两个场景下实现
undo日志版本链与read view 机制详解
事务回滚就是靠undo回滚日志,用两个隐藏字段 trx_id (事务id)和 roll_pointer (回滚指针)把这些日志串联起来形成一个历史记录版本链