Mysql数据库知识点(必知)

目录

1为什么使用数据索引能提高效率

2.B+树索引和哈希索引的区别

3.哈希索引的优势

4.哈希索引不适用的场景

5.什么是表分区?

6.表分区与分表的区别?

7.表分区有什么好处?

8.在MVCC并发控制中,读操作可以分成两类

9.行级锁定的优点

10.行级锁定的缺点

11.MySQL优化

12.key和index的区别

13.Mysql 中MyISAM和InnoDB的区别有哪些?

14.数据库表创建注意事项

15.聊聊索引在哪些场景下会失效?

16.聊聊事务隔离级别,以及可重复读实现原理

16.1 数据库四大隔离级别

16.2 Read View可见性规则

16.3 可重复读实现原理


1为什么使用数据索引能提高效率

  • 数据索引的存储是 有序的

  • 在有序的情况下, 通过索引查询一个数据是无需遍历索引记录的

  • 极端情况下,数据索引的查询效率为二分法查询效率,趋近于log2(N)

2.B+树索引和哈希索引的区别

B+树是一个平衡的多叉树,从根节点到每个叶子节点的高度差值不超过1,而且同层级的节点间有指针相互链接,是有序的,如下图:

图片

哈希索引就是采用一定的哈希算法,把键值换算成新的哈希值,检索时不需要类似B+树那样从根节点到叶子节点逐级查找,只需一次哈希算法即可,是无序的,如下图所示:

图片

3.哈希索引的优势

等值查询,哈希索引具有绝对优势(前提是:没有大量重复键值,如果大量重复键值时,哈希索引的效率很低,因为存在所谓的哈希碰撞问题。

4.哈希索引不适用的场景

  • 不支持 范围查询

  • 不支持索引完成排序

  • 不支持联合索引的最左前缀匹配规则

5.什么是表分区?

表分区,是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成

6.表分区与分表的区别?

分表:指的是通过一定规则, 将一张表分解成多 张不同的表。比如将用户订单记录根据时间成多个表

分表与分区的区别在于:分区从逻辑上来讲只有一张表 ,而分表则是将一张表分解成多张表。

7.表分区有什么好处?

  • 存储更多数据。分区表的数据可以分布在不同的物理设备上,从而高效地利用多个硬件设备。和单个磁盘或者文件系统相比,可以存储更多数据

  • 优化E询。在where语句中包含分区条件时,可以只扫描一个或多 个分区表来提高查询效率;涉及sum和count语句时,也可以在多个分区上并行处理,最后汇总结果。

  • 分区表更容易维护。例如:想批量删除大量数据可以清除整个分区。

  • 避免某些特殊的瓶颈,例如InnoDB的单个索引的互斥访问, ext3问价你系统的inode锁竞争等。

8.在MVCC并发控制中,读操作可以分成两类

快照读(snapshot read):读取的是记录的可见版本(有可能是历史版本),不用加锁(共享读锁s锁也不加,所以不会阻塞其他事务的写)

当前读(currentread):读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录

9.行级锁定的优点

  • 当在许多线程中访问不同的行时只存在少量锁定冲突。

  • 回滚时只有少量的更改

  • 可以长时间锁定单一的行。

10.行级锁定的缺点

比页级或表级锁定占用更多的内存。当在表的大部分中使用时,比页级或表级锁定速度慢,因为你必须获取更多的锁。如果你在大部分数据上经常进行GROUP BY操作或者必须经常扫描整个表,比其它锁定明显慢很多。用高级别锁定,通过支持不同的类型锁定,你也可以很容易地调节应用程序,因为其锁成本小于行级锁定。

11.MySQL优化

  • 1.「表结构优化」

    • 1.1拆分字段

    • 1.2字段类型的选择

    • 1.3字段类型大小的限制

    • 1.4合理的增加冗余字段

    • 1.5新建字段一定要有默认值

  • 2.「索引方面」

    • 2.1索引字段的选择

    • 2.2利用好mysql支持的索引下推,覆盖索引等功能

    • 2.3唯一索引和普通索引的选择

  • 3.「查询语句方面」

    • 3.1避免索引失效

    • 3.2合理的书写where条件字段顺序

    • 3.3小表驱动大表

    • 3.4可以使用force index()防止优化器选错索引

  • 4.「分库分表」

12.key和index的区别

key是数据库的物理结构,它包含两层意义和作用,一是约束(偏 重于约束和规范数据库的结构完整性) ,二是索引(辅助查询 用的)。包括primary key, unique key, foreign key等

index是数据库的物理结构,它只是辅助查询的,它创建时会在另外的表空间(mysql中的innodb表空间) 以-个类似目录的结 构存储。索引要分类的话,分为前缀索引、全文本索引等;

13.Mysql 中MyISAM和InnoDB的区别有哪些?

  • InnoDB支持事务, MyISAM不支持

  • InnoDB支持外键,而MylSAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败;

  • InnoDB是聚集索引,数据文件是和索引绑在一起,必须要有主键,通过主键索引效率高。

  • InnoDB不保存 表的具体行数,执行select count(*) from table时需要全表扫描。

  • Innodb不支持全文索引,而MyISAM支持全文索引,查询效率上MyISAM要高;

14.数据库表创建注意事项

1、字段名及字段配制合理性

  • 剔除关系不密切的字段; 1字段命名要有规则及相对应的含义(不要一部分英文,一部分拼音,还有类似a.b.c这样不明含义的字段) ;

  • 字段命名尽量不要使用缩写(大多数缩写都不能明确字段含义) ;

  • 字段不要大小写混用(想要具有可读性,多个英文单词可使用下划线形式连接) ;

  • 字段名 不要使用保留字或者关键字;

  • 保持字段名和类型的一致性;

  • 慎重选择数字类型; 给文本字段留足余量;

2、系统特殊字段处理及建成后建议

  • 添加删除标记(例如操作人、删除时间) ;

  • 建立版本机制;

3、表结构合理性配置

  • 多型字段的处理 ,就是表中是否存在字段能够分解成更小独立的几部分(例如:人可以分为男人和女人) ;

  • 多值字段的处理,可以将表分为三张表,这样使得检索和排序更加有调理,且保证数据的完整性!

4、其它建议

  • 对于大数据字段,独立表进行存储,以便影响性能(例如:简介字段) ;

  • 使用varchar类 型代替char,因为varchar 会动态分配长度,char指定长度是固定的; 给表创建主键,对于没有主键的表,在查询和索引定义上有一定的影响;

  • 避免表字段运行为null,建议设置默认值(例如: int类型设置默认值为0) 在索引查询上,效率立显; 1建立索引,最好建立在唯-和非空的字段上,建立太多的索引对后期插入、更新都存在一定的影响(考虑实际情况来创建) ; 

15.聊聊索引在哪些场景下会失效?

  1. 查询条件包含or,可能导致索引失效

  2. 如何字段类型是字符串,where时一定用引号括起来,否则索引失效

  3. like通配符可能导致索引失效。

  4. 联合索引,查询时的条件列不是联合索引中的第一个列,索引失效。

  5. 在索引列上使用mysql的内置函数,索引失效。

  6. 对索引列运算(如,+、-、*、/),索引失效。

  7. 索引字段上使用(!= 或者 < >,not in)时,可能会导致索引失效。

  8. 索引字段上使用is null, is not null,可能导致索引失效。

  9. 左连接查询或者右连接查询查询关联的字段编码格式不一样,可能导致索引失效。

  10. mysql估计使用全表扫描要比使用索引快,则不使用索引。

16.聊聊事务隔离级别,以及可重复读实现原理

16.1 数据库四大隔离级别

为了解决并发事务存在的脏读、不可重复读、幻读等问题,数据库大叔设计了四种隔离级别。分别是读未提交,读已提交,可重复读,串行化(Serializable)。

  • 读未提交隔离级别:只限制了两个数据不能同时修改,但是修改数据的时候,即使事务未提交,都是可以被别的事务读取到的,这级别的事务隔离有脏读、重复读、幻读的问题;

  • 读已提交隔离级别:当前事务只能读取到其他事务提交的数据,所以这种事务的隔离级别解决了脏读问题,但还是会存在重复读、幻读问题;

  • 可重复读:限制了读取数据的时候,不可以进行修改,所以解决了重复读的问题,但是读取范围数据的时候,是可以插入数据,所以还会存在幻读问题;

  • 串行化:事务最高的隔离级别,在该级别下,所有事务都是进行串行化顺序执行的。可以避免脏读、不可重复读与幻读所有并发问题。但是这种事务隔离级别下,事务执行很耗性能。

四大隔离级别,都会存在哪些并发问题呢

隔离级别脏读不可重复读幻读
读未提交
读已提交×
可重复读××
串行化×××

16.2 Read View可见性规则

变量描述
m_ids当前系统中那些活跃(未提交)的读写事务ID, 它数据结构为一个List。
max_limit_id表示生成Read View时,系统中应该分配给下一个事务的id值。
min_limit_id表示在生成Read View时,当前系统中活跃的读写事务中最小的事务id,即m_ids中的最小值。
creator_trx_id创建当前Read View的事务ID

Read View的可见性规则如下:

  1. 如果数据事务ID trx_id < min_limit_id,表明生成该版本的事务在生成Read View前,已经提交(因为事务ID是递增的),所以该版本可以被当前事务访问。

  2. 如果trx_id>= max_limit_id,表明生成该版本的事务在生成Read View后才生成,所以该版本不可以被当前事务访问。

  3. 如果 min_limit_id =<trx_id< max_limit_id,需要分3种情况讨论

  • 1)如果m_ids包含trx_id,则代表Read View生成时刻,这个事务还未提交,但是如果数据的trx_id等于creator_trx_id的话,表明数据是自己生成的,因此是可见的。

  • 2)如果m_ids包含trx_id,并且trx_id不等于creator_trx_id,则Read View生成时,事务未提交,并且不是自己生产的,所以当前事务也是看不见的;

  • 3)如果m_ids不包含trx_id,则说明你这个事务在Read View生成之前就已经提交了,修改的结果,当前事务是能看见的。

16.3 可重复读实现原理

数据库是通过加锁实现隔离级别的,比如,你想一个人静静,不被别人打扰,你可以把自己关在房子,并在房门上加上一把锁!串行化隔离级别就是加锁实现的。但是如果频繁加锁,性能会下降。因此设计数据库的大叔想到了MVCC。

可重复读的实现原理就是MVCC多版本并发控制。在一个事务范围内,两个相同的查询,读取同一条记录,却返回了不同的数据,这就是不可重复读。可重复读隔离级别,就是为了解决不可重复读问题。

查询一条记录,基于MVCC,是怎样的流程呢?

  1. 获取事务自己的版本号,即事务ID

  2. 获取Read View

  3. 查询得到的数据,然后Read View中的事务版本号进行比较。

  4. 如果不符合Read View的可见性规则, 即就需要Undo log中历史快照;

  5. 最后返回符合规则的数据

InnoDB 实现MVCC,是通过Read View+ Undo Log实现的,Undo Log保存了历史快照,Read View可见性规则帮助判断当前版本的数据是否可见。

可重复读(RR)隔离级别,是如何解决不可重复读问题的?

假设存在事务A和B,SQL执行流程如下

图片

在可重复读(RR)隔离级别下,一个事务里只会获取一次read view,都是副本共用的,从而保证每次查询的数据都是一样的。

假设当前有一张core_user表,插入一条初始化数据,如下:

图片

基于MVCC,我们来看看执行流程

1、A开启事务,首先得到一个事务ID为100

2、B开启事务,得到事务ID为101

3、事务A生成一个Read View,read view对应的值如下

变量
m_ids100,101
max_limit_id102
min_limit_id100
creator_trx_id100

然后回到版本链:开始从版本链中挑选可见的记录:

图片

由图可以看出,最新版本的列name的内容是孙权,该版本的trx_id值为100。开始执行read view可见性规则校验:

min_limit_id(100)=<trx_id(100)<102;
creator_trx_id = trx_id =100;

由此可得,trx_id=100的这个记录,当前事务是可见的。所以查到是name为孙权的记录。

4、事务B进行修改操作,把名字改为曹操。把原数据拷贝到undo log,然后对数据进行修改,标记事务ID和上一个数据版本在undo log的地址。

图片

5、事务B提交事务

6、事务A再次执行查询操作,因为是RR(可重复读)隔离级别,因此会复用老的Read View副本,Read View对应的值如下

变量
m_ids100,101
max_limit_id102
min_limit_id100
creator_trx_id100

然后再次回到版本链:从版本链中挑选可见的记录:

图片

从图可得,最新版本的列name的内容是曹操,该版本的trx_id值为101。开始执行read view可见性规则校验:

min_limit_id(100)=<trx_id(101)<max_limit_id(102);
因为m_ids{100,101}包含trx_id(101),
并且creator_trx_id (100) 不等于trx_id(101)

所以,trx_id=101这个记录,对于当前事务是不可见的。这时候呢,版本链roll_pointer跳到下一个版本,trx_id=100这个记录,再次校验是否可见:

min_limit_id(100)=<trx_id(100)< max_limit_id(102);
因为m_ids{100,101}包含trx_id(100),
并且creator_trx_id (100) 等于trx_id(100)

所以,trx_id=100这个记录,对于当前事务是可见的,所以两次查询结果,都是name=孙权的那个记录。即在可重复读(RR)隔离级别下,复用老的Read View副本,解决了不可重复读的问题。

17.一条 Sql 语句查询偶尔慢会是什么原因?

  • 「1. 数据库在刷新脏页」

    • 比如 「redolog 写满了」「内存不够用了」释放内存如果是脏页也需要刷,mysql 「正常空闲状态刷脏页」

  • 「2. 没有拿到锁」

18.删除表数据后表的大小却没有变动,这是为什么?

在使用 delete 删除数据时,其实对应的数据行并不是真正的删除,是「逻辑删除」,InnoDB 仅仅是将其「标记成可复用的状态」,所以表空间不会变小

 

来源:database.51cto.com/art/202010/628634.htm

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值