MySQL面试必备+Explain的讲解+简单优化+MyISAM、InnoDB存储引擎区别+MySQL为什么选择B+树索引+MySQL中的锁

MySQL存储引擎

区别(MyISAM, InnoDB)

1,innodb支持事务,myisam不支持事务
2,innodb支持外键,而myisam不支持。对一个支持外间的innodb转换为myisam时会失败
3,innodb不保存表的具体行数,执行 select count(*)from table时会全表扫描,而myisam用一个变量保存了整个表的行数,执行上述语句只需读出该变量的值就行,速度很快
4,innodb不支持全文检索,而myisam支持全文检索,查询效率比innodb高
5,innodb支持行级锁,myisam锁的粒度是表级
6,myisam表示保存成文件的形式,在跨平台的数据转移中,使用myisam存储会省去不少的麻烦。

==========
myisam不支持主外键
innodb支持

myisam管理的是非事务表,提供高速的存储和检索,以及全文检索
innodb支持事务,具有众多的特性,包括ACID

A:原子性

C:一致性

I:隔离性

D:永久性


数据库索引的作用?缺点是什么?

创建索引可以大大提高系统的性能。
1、通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
2、可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
3、可以加快表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
4、在使用分组和排序,字句进行数据检索时,同样可以显著减少查询中分组和排序的时间。

5、通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

缺点:
a、创建索引和维护索引要耗时间,这种时间随着数据和量的增加而增加。
b、索引要占用物理空间。
c、当对表中的数据进行增加、删除、修改时,索引也要动态维护,这样就降低了数据的维护速度。


MySQL中数据结构为什么选择用B+树?

Hash的查找时间复杂度是O(1),查找确实很快,无论找哪一个数,都可以一次性找到,但是有一个问题,我们平时找数据还会根据条件查找,where。。。。 大于。。。小于。。。。。 between and 。。。。还有排序。。。这时的时间复杂度就变成了O(n),相比hash二叉树更稳定,任何时间复杂度都是log(n),所以MySQL没有用hash。

==============

为什么不用二叉树?
二叉树的定义是“左小右大”,但会出现极端的情况,比如第一个数字是1,然后后面依次出现2,3,4,5,6……就会形成一个链,此种情况就是 “右倾”

================
平衡二叉树会旋转,根节点会随着数据的变化而变化。理论上讲此时比较次数和查找次数都很理想,但是有一个问题随着数据量的增多,树的高度也变大了,而查找的速度和树的高度成正相关!并且磁盘的IO次数也是和树的高度正相关的。

==================
二叉树一个节点上只能挂两个节点,B树一个节点上最多可以挂3个节点,这样做的好处是可以降低树的高度,因为中间还有一个节点。B树的节点不仅存储数据的指针还存储数据的data,但每一页的存储空间又是有限的,所以他相比B+树(B+树的非叶子节点只存储数据的指针,数据都存在叶子节点)的高度会高,会增加磁盘的io。

======================
B+树有两种数据结构,最底层叶子节点是链表,非链表节点是树形结构,B+树将所有数据都放在叶子节点,获取所有节点不再需要中序遍历(左–中--右),并且节点和节点之间还有指针相连。这样就加快了范围查找。


mysql中的锁

在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互拆要求的满足。

行级锁

是MySQL中颗粒度最细的一种锁,表示只针对当前操作的行进行加锁,行级锁大大减少了数据库操作的冲突。其加锁颗粒度最小,但加锁开销也最大。

特点:开销大,加锁慢,会出现死锁的情况,颗粒度最小,发生冲突的可能想也最低,并发度也最高

冲突少,加锁慢
(是MySQL中颗粒度最细的一种锁,表示只针对当前操作的行进行加锁,行级锁大大减少了数据库操作的冲突。其加锁颗粒度最小,但加锁开销也最大。, 特点:开销大,加锁慢,会出现死锁的情况,颗粒度最小,发生冲突的可能想也最低,并发度也最高)

表级锁

是MySQL中颗粒度最大的一种锁,表示对当前操作的整张表进行加锁,他实现简单,资源消耗也少,被大部分MySQL引擎支持

特点:开销小,加锁快,不会出现死锁,速颗粒度较大,发生冲突的概率较高,并发度最低

速度快,冲突多
(是MySQL中颗粒度最大的一种锁,表示对当前操作的整张表进行加锁,他实现简单,资源消耗也少,被大部分MySQL引擎支持, 特点:开销小,加锁快,不会出现死锁,速颗粒度较大,发生冲突的概率较高,并发度最低)

页级锁

是MySQL中介于行级锁和表级所之间的锁,是他们折中的一种锁,一次锁相邻的一组记录

特点:开锁和加锁介于表锁和行锁之间,会出现死锁,粒度也是介于行锁和表锁之间,并发度一般

介于行锁和表锁之间
(是MySQL中介于行级锁和表级所之间的锁,是他们折中的一种锁,一次锁相邻的一组记录, 特点:开锁和加锁介于表锁和行锁之间,会出现死锁,粒度也是介于行锁和表锁之间,并发度一般)


数据库优化

什么是优化?

合理的安排资源,调整系统参数使MySQL运行更快更节省资源

优化是多方面的,包括查询、更新、服务器等

优化原则:减少资源的瓶颈,减少资源占用、增加系统的反应速度


Explain查看执行计划(在查询语句前面加explain)

字段讲解

select_type:表示select语句的类型

  1. simple
    简单查询,其中不包括连接查询和子查询
  2. primary
    主查询,或者是最外面的查询语句
  3. union
    连接查询的第二个或后面的查询语句
  4. dependent union
    union中的第二个或后面的select语句,取决于外面的查询
  5. union result
    连接查询的结果
  6. sub_query
    子查询的第一个select语句
  7. dependent_subquery
    子查询 第一个select语句,取决于外面的 查询
  8. derived
    select (from 字句的子查询)

type:表示表的连接类型

  1. system仅有一行,这是const类型的特类,平时不会出现,这个可以忽略不计

  2. const数据表只有一个匹配行,常用于primary key 或者unique索引查询,也可以理解为const是最优的

  3. eq_ref可以用于使用=比较带索引的查询,它用在一个索引的所有部分被连接使用并且索引是primary key或者unique

  4. ref查询条件既不是primary key也不是unique的情况。可用于=或者<或者>操作

  5. ref_or_null该类型如同ref,但是添加了MySQL可以专门搜索包含null值的行。在解决子查询中经常使用该连接类型的优化

  6. index_merge该连接类型表示使用了索引合并优化方法

  7. unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高

  8. index_subquery该连接类型类似于unique_subquery,可以替换子查询

  9. range只检索指定范围的行,使用一个索引来选择行

  10. index该连接类型与all相同,通常比all快一点,因为索引文件通常比数据文件小

  11. all进行全表扫描,性能最差

这5种情况都是很理想的索引使用情况
(system, const, eq_ref, ref, ref_or_null)

possible_keys

指出MySQL中能使用哪一个索引在该表中找到行,如果该列为null,说明没有使用索引,可以对该列创建索引来提高性能

  1. key:显示MySQL实际决定使用的索引(键),如果没有选择索引,键是null。可以强制使用索引或者忽略索引

  2. key_len:显示MySQL决定使用键的长度如果键是null,则长度是null

  3. ref:显示使用哪一个列或者常数与key一起从表中选择行

  4. rows:显示MySQL认为它执行查询必须检查的行数

  5. extra:该列包含MySQL解决查询的详细信息


MySQL索引使用注意项

1、在使用Like关键字进行查询的查询语句中,如果匹配字符串的第一个字符为%时,索引不起作用。只有%不在第一个位置时索引才起作用

2、复合索引遵循最左前缀原则,即在查询条件中使用了复合索引的第一个字段,索引才会被使用,因此复合索引中的索引列的位置至关重要。

3、只要列中包含有null值都不会抱哈在索引中,复合索引中只要有一列含有null值,那么这一列对于复合索引就是无效的

4、在查询语句的查询条件中,只有OR关键字,且OR前后的两个条件中的列都是索引时,索引才会生效

概要
(1、在使用Like关键字进行查询的查询语句中,如果匹配字符串的第一个字符为%时,索引不起作用。只有%不在第一个位置时索引才起作用, 2、复合索引遵循最左前缀原则,即在查询条件中使用了复合索引的第一个字段,索引才会被使用,因此复合索引中的索引列的位置至关重要。, 3、只要列中包含有null值都不会抱哈在索引中,复合索引中只要有一列含有null值,那么这一列对于复合索引就是无效的, 4、在查询语句的查询条件中,只有OR关键字,且OR前后的两个条件中的列都是索引时,索引才会生效)


子查询的优化:

子查询时,MySQL需要创建临时表,查询完之后再删除,所以子查询的速度会受到一定影响,所以可以用连接查询join代替子查询,连接查询不需要建立临时表,其速度比子查询快。

数据库结构的优化

一个好的数据库设计方案,对于数据库的性能往往起到事半功倍的效果。
需要考虑数据冗余,查询和更新的速度,字段的数据类型是否合理等多方面

  • 将字段很多的表分解成多张表

对于字段很多的表,如果有些字段使用频率很低,而有些字段使用频率很高,可以将那些使用频率低的字段分离出来,形成一个新表。因为当一个表的数据量很大的时候,会由于使用低的字段存在而变的很慢。

  • 增加中间表

对于需要经常联合查询的表,可以新建一张中间表。
通过中间表,将需要通过联合查询的数据插入到中间表中,然后将原来的联合查询改为查询对中间表的查询

  • 增加冗余字段

设计表的时候应尽量遵循范式理论的规约,尽量减少冗余字段,让数据库设计看起来精致、优雅。但是,合理的假如冗余字段可以提高查询速度。
注意:冗余字段的值在一个表修改了,在另外一张表中也要同时修改,否则会出现数据不一致的情况

  • 服务器硬件优化
  1. 配置较大的内存

  2. 内存的io比硬盘快的多,可以增加系统的缓冲区容量,是数据在内存中停留的时间更长,以减少磁盘io

  3. 配置告诉磁盘,如SSD

  4. 合理分配磁盘IO

  5. 把磁盘io分散到多个设备上,以减少资源的竞争,提高并行操作能力

  6. 配置多核处理器

MySQL是多线程的数据库,多处理器可以提高同时执行多个线程的能力


MySQL查询优化具体方法

  • 不要在列上进行计算,这样将导致索引失效,从而进行全表扫描

  • 尽量避免使用 != not in <>等否定操作,可以用or来连接条件

  • 永远用小结果集驱动大结果集

  • 永远为每张表设置一个id

  • 当只有一条数据时使用limit 1

  • 尽量不要在语句中使用函数

  • 避免使用select * ,应该是用到哪个字段就写哪个字段

  • (不要在列上进行计算,这样将导致索引失效,从而进行全表扫描, 尽量避免使用 != not in <>等否定操作,可以用or来连接条件, 永远用小结果集驱动大结果集, 永远为每张表设置一个id, 当只有一条数据时使用limit 1, 尽量不要在语句中使用函数, 避免使用select * ,应该是用到哪个字段就写哪个字段)

MySQL参数优化

MySQL的配置参数都在my.conf 或者 my.ini文件的[mysqld]组中

  1. key_buf_size:索引缓冲区的大小。索引缓冲区是所有线程共享。增加索引缓冲区可以得到更好的处理索引,但这个值不是越大越好,他的值取决于内存大小,如果太大会导致系统频繁换页,也会降低系统的使用性能

  2. table_cache:表示同时打开的的表的个数。这个值越大表示能同时打开的表的个数也越多,这个值也不是越大越好

  3. sort_buf_size:表示排序缓冲区的大小,这个值越大,进行排序的速度也越快

  4. innodb_buf_pool_size:表示innodb类型的表和索引的最大缓存,这个值越大查询的速度越快,但是太大会影响系统性能

  5. max_connections:表示数据库的最大连接数,要注意连接会占用内存资源,过多连接会导致MySQL僵死

  6. thread_cache_size:表示可以复用的线程数量,如果有很多新的线程,可以适当增大改参数的数值

  7. wait_timeout:表示服务器在关闭一个连接时等待行动的秒数。默认值是28800


事务隔离级别

  • 读未提交

允许脏读,也就是可能读取到其他会话中未提交事务修改的数据–》会发生脏读、不可重复读、虚读

  • 读已提交

只能读取到已提交的数据。解决脏读,但不可重复读、虚读还有发生

  • 可重复读

在一个事务内的查询都是事务开始时刻一致的,innodb默认级别。解决了脏读、不可重复读,但是虚读仍有可能发生

  • 串行化

完全串行化的读,每次读都要获得表级共享锁,读写相互都会阻塞,可以保证不同事务之间互斥,避免了脏读、不可重复读和幻读

脏读

指一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这事另一个事务也访问了这个数据,然后使用了这个数据

不可重复读

在同一个事务中,两个相同的查询返回了不同的结果(读取数据本身的对比),比如:在事务1期间内,事务2对事务1操作的数据进行了修改,由于事务2的修改,事务1前后读取的数据有可能不一样

幻读

第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行,同时第二个事务也修改了这个表中的数据,这种修改是向表中插入一行新数据,那么第一个事务就会出现我明明修改了所有数据,为什么还有一个数据未修改,就好像幻读一样


发布了4 篇原创文章 · 获赞 4 · 访问量 103

猜你喜欢

转载自blog.csdn.net/qq_40585384/article/details/105420602