MySQL
-
数据库三大范式
第一范式(1NF):第一范式要求表中的每一列只包含原子值,原子值是不可分割的值,不能进一步细分。这意味着必须将重复的值组分隔到各自的表中。
第二范式(2NF):第二范式要求表中的每个非键列仅依赖于主键。这意味着任何不是主键一部分的列都必须在功能上依赖于整个主键。
第三范式(3NF):第三范式要求数据库中没有传递依赖关系。这意味着,如果非键列依赖于另一个非键列,则必须将其从表中删除并放置在单独的表中。 -
MySQL存储引擎MyIsam和InnoDB有哪些区别。
1.InnoDB 支持事务,MyISAM 不支持事务
2.对一个包含外键的 InnoDB 表转为 MYISAM 会失败, MyISAM不支持外键
3.InnoDB 不保存表的具体行数需要全表扫描,而MyISAM 用一个变量保存了整个表的行数
4.InnoDB 最小的锁粒度是行锁,MyISAM 最小的锁粒度是表锁。一个更新语句会锁住整张表,导致其他查询和更新都会被阻塞,因此并发访问受限 5.系统崩溃后,MyISAM恢复起来更困难,能否接受,不能接受就选 InnoDB
6.InnoDB的主键索引的叶子节点存储的是行数据,因此主键索引非常高效。
7.MyISAM索引的叶子节点存储的是行数据地址,需要一次寻址的操作才能获取到数据。备份及恢复:
MyISAM: 数据是以文件的形式存储,所以在跨平台的数据转移中会很方便,在备份和恢复时可单独针对某个表进行操作
InnoDB: 拷贝数据文件、备份 binlog,或者用 mysqldump,在数据量达到几十G的时候就相对痛苦了 -
什么是索引?都有哪些类型?有什么优点和缺点?
索引是数据库中为了提高数据查询效率而创建的一种数据结构。主要作用是帮助查询进行快速定位,而不需要扫描整个数据表。
索引可以分为多种类型,其中常见的类型包括:B-Tree 索引、Hash 索引、Bitmap 索引
索引有以下优点:提高查询效率,可以快速定位数据、提高数据的读取速度、减小数据的读取负荷
索引也有以下缺点:需要额外的空间存储索引、索引的更新操作会变慢、索引会使数据的写入变慢哈希索引:
优点:1.索引本身只存储 hash code,所以结构很紧凑,并且查找速度很快
限制:
1.索引中的 hash code 是顺序存储的,但是 hash code 对应的数据并不是顺序的,所以无法用于排序
2.不支持部分索引列匹配查找,因为哈希索引是使用索引列的全部内容来计算 hash code
3.只支持等值比较,不支持范围查询
4.如果哈希冲突严重时,必须遍历链表中所有行指针
5.哈希冲突严重的话,索引维护操作的代价也很高 -
B树和B+树的区别,聚集索引和非聚集索引的区别。什么是回表,怎么减少回表?
B树:二叉树,每个结点只存储一个关键字,等于则命中,小于走左结点,大于走右结点;
B-树:多路搜索树,每个结点存储M/2到M个关键字,非叶子结点存储指向关键字范围的子结点;所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;
B+树:在B树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中;
B+树的优点:
1. B+树能显著减少IO次数,提高效率
2. B+树的查询效率更加稳定,因为数据放在叶子节点
3. B+树能提高范围查询的效率,因为叶子节点指向下一个叶子节点聚集索引:
产生原因:
当给表加上主键的时候,这个表就会转化成我们刚刚所说的B+树的形状,相当于整个表就变成了一个索引,所以这就成为聚集索引
查询原理:
每次查找的时候,都是根据主键进行查找的,也就是非叶子结点中存储的就是主键中的数据,每次查找都要找到相应的叶子结点,然后取到相应的数据
缺点:
有了聚集索引,那么查询自然是快了许多,但是实际上为增,删等写入数据的操作变慢
原因是因为每次写入操作都需要进行平衡二叉树的判断,修改树的结构,这样肯定是浪费了时间的非聚集索引:
产生原因:
每次当我们定义一个字段(非主键)为非聚集索引,那么数据库就会将这个表中的该字段复制一份构成一颗B+树,这棵B+树中的叶子结点存储的是相应的主键,非叶子结点存储当然是索引指针了
我们定义多个字段分别为非聚集索引,那么就会生成多颗B+树,并且是不互相干扰的
查询原理:
非聚集索引的查找其实就是最终查找到相应的主键,然后再通过聚集索引树去查找数据——所以可以看做是二次查 找回表:
非主键索引进行查询,select所要获取的字段不能通过非主键索引获取到,需要通过非主键索引获取到的主键,从聚集索引再次查询一遍,获取到所要查询的记录,这个查询的过程就是回表。
减少回表:
1. 缓存:通过缓存常用数据,减小访问数据库的频率,从而减少回表。
2. 批量请求:通过一次请求获取多个数据,减少回表的次数。
3. 建立联合索引:建立索引以加快数据查询速度。 -
为什么会有索引失效的情况,索引调优有哪些方法?
SQL语句没有使用到索引,回表查询整张表。
索引调优:
1. 最左前缀法则、尽量不使用函数或+、-、!=、 <、>、is null、or
2. like 导致索引失效:like "%张三"
3. 使用主键进行order by
4. explain分析SQL语句、查看可能用到的索引进行优化
type: 依次从最优到最差分别为:system > const > eq_ref > ref > range > index > ALL(一般来说,得保证查询达到range级别,最好达到ref) -
MySQL中的锁有哪些?什么是next-key lock?
行锁表锁:只有明确知道主键,才会执行行锁,否则执行表锁。没有索引会使用表锁
- 表级锁:对整张表上锁,不允许其他线程读写数据,主要使用的是LOCK TABLES语句。
- 行级锁:锁定表中的某一行数据,不允许其他线程读写该行数据,主要使用的是SELECT...FOR UPDATE语句。行锁在 InnoDB 中是基于索引实现的,所以一旦某个加锁操作没有使用索引,那么该锁就会退化为表锁。
表锁: 意向锁:意向锁的主要作用是判断表里是否有记录被加锁,也就是表里是否有行级锁。当需要加一个表级锁时,需要判断表里是否有独占锁,如果没有意向锁就需要遍历表里所有记录。
行锁: 记录锁:为一个行的数据上锁,主要使用的是UPDATE语句。 间隙锁:存在于非唯一索引中,使用间隙锁锁住的是一个区间(不包含下标两个行),而不仅仅是这个区间中的每一条数据。 临键锁:(next-key lock)通过临建锁可以解决幻读的问题。每个数据行上的非唯一索引列上都会存在一把临键锁,当某个事务持有该数据行的临键锁时,会锁住一段左开右闭区间的数据。InnoDB 中行级锁是基于索引实现的,临键锁只与非唯一索引列有关,在唯一索引列(包括主键列)上不存在临键锁。
-
乐观锁与悲观锁。
乐观锁和悲观锁是数据库并发控制的两种策略。 1.乐观锁是一种更为宽松的并发控制策略,它基于一种无阻塞的思想,即相信在大多数情况下,并发冲突是不会发生的。乐观锁通常通过版本号等机制来实现,在更新数据时,会先检查数据的版本号是否与预期的版本号一致,如果不一致说明该数据已经被其他事务修改,此时更新操作会失败。 2.悲观锁是一种更为严格的并发控制策略,它基于一种假设最坏情况的思想,即并发冲突总是会发生。悲观锁通常通过互斥锁等机制实现,在访问数据时,会先对数据加锁,在该事务结束前保持锁定状态,阻止其他事务对数据进行修改。
-
Mysql的事务隔离级别有哪些?MVCC是什么?
读未提交、读已提交、可重复读、可串行化 MVCC是MySQL等数据库系统中提供的一种并发控制机制。在使用MVCC时,每个事务看到的数据版本是独立的,互不干扰。MVCC的核心思想就是维护多个版本的数据,每个事务仅能看到在事务开始时快照的版本。这样就可以实现高效的并发控制。
组成:
1. 表的隐藏字段:记录最近修改事务id字段(trx_id)、及上个版本的数据地址字段(roll_pointer)、row_id隐藏的主键在表没有指定主键时
2. undo log:记录数据各个版本修改历史即事务链
3. Read View:读试图,用于判断哪些版本可见
read View包含字段:
trx_list: 表示在生成 ReadView 时当前系统中活跃的读写事务的 事务id 列表
up_limit_id: 表示在生成 ReadView 时当前系统中活跃的读写事务中最小的 事务id
low_limit_id: 表示生成 ReadView 时系统中应该分配给下一个事务的 id 值
trx_id: 表示生成该 ReadView 的事务的 事务id版本未提交,不可见; 版本已提交,但是是在视图创建后提交的,不可见; 版本已提交,而且是在视图创建前提交的,可见。 -
脏读,不可重复读,幻读是什么?是怎么解决的。
脏读,幻读,不可重复读是数据库事务隔离级别中的三种读问题。
- 脏读:在一个事务中读取了另一个事务未提交的数据。 mvcc+悲观锁或乐观锁
- 不可重复读:一个事务多次读同一数据,但是由于其他事务的修改,每次读到的数据不同。mvcc
- 幻读:一个事务读到了另一个事务中新插入的数据,或者读不到另一个事务中删除的数据。mvcc+next-key locks 通过提高数据库的隔离级别,比如使用更高的事务隔离级别。
-
MySQL删除数据时的一些注意事项。
- 删除数据之前,先备份数据,以防止误删。
- 使用truncate语句比delete语句更高效,但是注意truncate语句不支持回滚。
- 在删除数据之前,应该评估一下该删除的数据的影响,以防止误删。
- 在删除数据时,可以使用LIMIT限制删除数量,防止意外删除过多的数据。
- 对于外键关联的表,需要考虑删除时的外键约束,防止数据不一致。
- 删除数据之后,应该对数据进行评估,确保删除后数据的一致性。
-
MySQL使用时的一些经验和优化。(索引怎么用,数据量大的时候如何切分,写SQL语句的一些习惯)
索引使用:
使用合适的索引,能够大大加快查询的速度
索引的字段要尽量在第一个条件中使用,否则索引就无法生效
对于经常使用的字段和频繁查询的字段需要建立索引
数据量大时的切分:
在数据量很大时可以考虑数据切分,比如按时间,地域等进行切分
切分数据能够减小单表数据量,减少数据存储的开销,提高查询的效率
写SQL语句的一些习惯:
使用合适的语句,如使用update instead of delete
设置合适的语句超时时间,避免因语句执行时间过长导致数据库压力
使用explain语句诊断语句的执行计划,避免使用不合适的语句 -
分库分表
分库分表的顺序应该是先垂直分,后水平分。
垂直切分: 拆分字段创建新表,一般是表中的字段较多,将不常用的,数据较大,长度较长(比如text类型字段)的拆分到“扩展表“。
水平切分:表里面的数据分多张,table1、table2、table3,按照某种规则(范围,HASH取模等),切分到多张表里面去。 但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈。
缺点:分库分表后,就成了分布式事务了。如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价; 如果由应用程序去协助控制,形成程序逻辑上的事务,