mysql如何实现索引机制
mysql中索引分三类:B+树索引、Hash索引、全文索引
InnoDB索引与MYISAM索引实现的区别是什么
1.InnoDB的辅助索引data域存储相应记录主键的值而不是地址
2.InnoDB的数据文件本身就是主索引文件
3.MyISAM的索引和数据是分开存储的
一个表中如果没有创建索引,那么还会创建B+树吗?
没有创建索引依然会创建B+树,会创建隐式主键。
1、什么是三大范式?
第一范式(1NF):字段(或属性)是不可分割的最小单元,即不会有重复的列,体现原子性
第二范式(2NF):满足 1NF 前提下,存在一个候选码,非主属性全部依赖该候选码,即存在主键,体现唯一性,专业术语则是消除部分函数依赖
第三范式(3NF):满足 2NF 前提下,非主属性必须互不依赖,消除传递依赖
2、什么是范式和反范式,以及各自优缺点?
范式是符合某一种级别的关系模式的集合。构造数据库必须遵循一定的规则。在关系数据库中,这种规则就是范式。
名称 优点 缺点
范式 范式化的表减少了数据冗余,数据表更新操作快、占用存储空间少。 查询时通常需要多表关联查询,更难进行索引优化
反范式 反范式的过程就是通过冗余数据来提高查询性能,可以减少表关联和更好进行索引优化 存在大量冗余数据,并且数据的维护成本更高
所以在平时工作中,我们通常是将范式和反范式相互结合使用。
1、索引的几种类型或分类?
1)从物理结构上可以分为聚集索引和非聚集索引两类:
聚簇索引指索引的键值的逻辑顺序与表中相应行的物理顺序一致,即每张表只能有一个聚簇索引,也就是我们常说的主键索引;
非聚簇索引的逻辑顺序则与数据行的物理顺序不一致。
2)从应用上可以划分为一下几类:
普通索引:MySQL 中的基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值,纯粹为了提高查询效率。通过 ALTER TABLE table_name ADD INDEX index_name (column) 创建;
唯一索引:索引列中的值必须是唯一的,但是允许为空值。通过 ALTER TABLE table_name ADD UNIQUE index_name (column) 创建;
主键索引:特殊的唯一索引,也成聚簇索引,不允许有空值,并由数据库帮我们自动创建;
组合索引:组合表中多个字段创建的索引,遵守最左前缀匹配规则;
全文索引:只有在 MyISAM 引擎上才能使用,同时只支持 CHAR、VARCHAR、TEXT 类型字段上使用。
2、索引的优缺点?
先来说说优点:创建索引可以大大提高系统的性能。
通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
既然增加索引有如此多的优点,为什么不对表中的每一个列都创建一个索引呢?这是因为索引也是有缺点的:
创建和维护索引需要耗费时间,这种时间随着数据量的增加而增加,这样就降低了数据的维护速度。
索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间。如果要建立聚簇索引,那么需要的空间就会更大。
3、索引设计原则?
选择唯一性索引;
唯一性索引的值是唯一的,可以更快速的通过该索引来确定某条记录。
为常作为查询条件的字段建立索引;
如果某个字段经常用来做查询条件,那么该字段的查询速度会影响整个表的查询速度。因此,为这样的字段建立索引,可以提高整个表的查询速度。
为经常需要排序、分组和联合操作的字段建立索引;
经常需要 ORDER BY、GROUP BY、DISTINCT 和 UNION 等操作的字段,排序操作会浪费很多时间。如果为其建立索引,可以有效地避免排序操作。
限制索引的数目;
每个索引都需要占⽤用磁盘空间,索引越多,需要的磁盘空间就越大,修改表时,对索引的重构和更新很麻烦。
小表不建议索引(如数量级在百万以内);
由于数据较小,查询花费的时间可能比遍历索引的时间还要短,索引可能不会产生优化效果。
尽量使用数据量少的索引;
如果索引的值很长,那么查询的速度会受到影响。此时尽量使用前缀索引。
删除不再使用或者很少使用的索引。
4、索引的数据结构?
索引的数据结构和具体存储引擎的实现有关,MySQL 中常用的是 Hash 和 B+ 树索引。
Hash 索引底层就是 Hash 表,进行查询时调用 Hash 函数获取到相应的键值(对应地址),然后回表查询获得实际数据.
B+ 树索引底层实现原理是多路平衡查找树,对于每一次的查询都是从根节点出发,查询到叶子节点方可以获得所查键值,最后查询判断是否需要回表查询.
5、Hash 和 B+ 树索引的区别?
Hash
1)Hash 进行等值查询更快,但无法进行范围查询。因为经过 Hash 函数建立索引之后,索引的顺序与原顺序无法保持一致,故不能支持范围查询。同理,也不支持使用索引进行排序。
2)Hash 不支持模糊查询以及多列索引的最左前缀匹配,因为 Hash 函数的值不可预测,如 AA 和 AB 的算出的值没有相关性。
3)Hash 任何时候都避免不了回表查询数据.
4)虽然在等值上查询效率高,但性能不稳定,因为当某个键值存在大量重复时,产生 Hash 碰撞,此时查询效率反而可能降低。
B+ Tree
1)B+ 树本质是一棵查找树,自然支持范围查询和排序。
2)在符合某些条件(聚簇索引、覆盖索引等)时候可以只通过索引完成查询,不需要回表。
3)查询效率比较稳定,因为每次查询都是从根节点到叶子节点,且为树的高度。
6、为何使用 B+ 树而非二叉查找树做索引?
我们知道二叉树的查找效率为 O(logn),当树过高时,查找效率会下降。另外由于我们的索引文件并不小,所以是存储在磁盘上的。
文件系统需要从磁盘读取数据时,一般以页为单位进行读取,假设一个页内的数据过少,那么操作系统就需要读取更多的页,涉及磁盘随机 I/O 访问的次数就更多。将数据从磁盘读入内存涉及随机 I/O 的访问,是数据库里面成本最高的操作之一。
因而这种树高会随数据量增多急剧增加,每次更新数据又需要通过左旋和右旋维护平衡的二叉树,不太适合用于存储在磁盘上的索引文件。
7、为何使用 B+ 树而非 B 树做索引?
在此之前,先来了解一下 B+ 树和 B 树的区别:
B 树非叶子结点和叶子结点都存储数据,因此查询数据时,时间复杂度最好为 O(1),最坏为 O(log n)。而 B+ 树只在叶子结点存储数据,非叶子结点存储关键字,且不同非叶子结点的关键字可能重复,因此查询数据时,时间复杂度固定为 O(log n)。
B+ 树叶子结点之间用链表相互连接,因而只需扫描叶子结点的链表就可以完成一次遍历操作,B 树只能通过中序遍历。
为什么 B+ 树比 B 树更适合应用于数据库索引?
B+ 树减少了 IO 次数。
由于索引文件很大因此索引文件存储在磁盘上,B+ 树的非叶子结点只存关键字不存数据,因而单个页可以存储更多的关键字,即一次性读入内存的需要查找的关键字也就越多,磁盘的随机 I/O 读取次数相对就减少了。
B+ 树查询效率更稳定
由于数据只存在在叶子结点上,所以查找效率固定为 O(log n),所以 B+ 树的查询效率相比B树更加稳定。
B+ 树更加适合范围查找
B+ 树叶子结点之间用链表有序连接,所以扫描全部数据只需扫描一遍叶子结点,利于扫库和范围查询;B 树由于非叶子结点也存数据,所以只能通过中序遍历按序来扫。也就是说,对于范围查询和有序遍历而言,B+ 树的效率更高。
9、什么是覆盖索引?
在 B+ 树的索引中,叶子节点可能存储了当前的键值,也可能存储了当前的键值以及整行的数据,这就是聚簇索引和非聚簇索引。 在 InnoDB 中,只有主键索引是聚簇索引,如果没有主键,则挑选一个唯一键建立聚簇索引。如果没有唯一键,则隐式的生成一个键来建立聚簇索引。
当查询使用聚簇索引时,在对应的叶子节点,可以获取到整行数据,因此不用再次进行回表查询。
10、什么是索引下推?
索引下推(Index condition pushdown) 简称 ICP,在 Mysql 5.6 版本上推出的一项用于优化查询的技术。
在不使用索引下推的情况下,在使用非主键索引进行查询时,存储引擎通过索引检索到数据,然后返回给 MySQL 服务器,服务器判断数据是否符合条件。
而有了索引下推之后,如果存在某些被索引列的判断条件时,MySQL 服务器将这一部分判断条件传递给存储引擎,然后由存储引擎通过判断索引是否符合 MySQL 服务器传递的条件,只有当索引符合条件时才会将数据检索出来返回给 MySQL 服务器。
索引条件下推优化可以减少存储引擎查询基础表的次数,也可以减少 MySQL 服务器从存储引擎接收数据的次数。
2、MyISAM 和 InnoDB 的区别?
1)InnoDB 支持事务,而 MyISAM 不支持。
2)InnoDB 支持外键,而 MyISAM 不支持。因此将一个含有外键的 InnoDB 表 转为 MyISAM 表会失败。
3)InnoDB 和 MyISAM 均支持 B+ Tree 数据结构的索引。但 InnoDB 是聚集索引,而 MyISAM 是非聚集索引。
4)InnoDB 不保存表中数据行数,执行 select count(*) from table 时需要全表扫描。而 MyISAM 用一个变量记录了整个表的行数,速度相当快(注意不能有 WHERE 子句)。
那为什么 InnoDB 没有使用这样的变量呢?因为InnoDB的事务特性,在同一时刻表中的行数对于不同的事务而言是不一样的。
5)InnoDB 支持表、行(默认)级锁,而 MyISAM 支持表级锁。
InnoDB 的行锁是基于索引实现的,而不是物理行记录上。即访问如果没有命中索引,则也无法使用行锁,将要退化为表锁。
6)InnoDB 必须有唯一索引(如主键),如果没有指定,就会自动寻找或生产一个隐藏列 Row_id 来充当默认主键,而 Myisam 可以没有主键。
3、InnoDB 的四大特性?
插入缓冲insert buffer)
二次写(double write)
自适应哈希索引(ahi)
预读(read ahead)
4、InnoDB 为何推荐使用自增主键?
自增 ID 可以保证每次插入时 B+ 树索引是从右边扩展的,因此相比自定义 ID (如 UUID)可以避免 B+ 树的频繁合并和分裂。如果使用字符串主键和随机主键,会使得数据随机插入,效率比较差。
5、如何选择存储引擎?
默认使用 InnoDB,MyISAM 适用以插入为主的程序,比如博客系统、新闻门户。
2、什么是事务的四大特性(ACID)?
原子性: 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用
一致性: 事务执行前后,数据保持一致,多个事务对同一个数据读取的结果是相同的
隔离性: 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的
持久性: 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
4、事务的并发问题?
脏读、幻读和不可重复读。
5、什么是脏读、幻读和不可重复度?
脏读:一个事务读取到另一个事务尚未提交的数据。 事务 A 读取事务 B 更新的数据,然后 B 回滚操作,那么 A 读取到的数据是脏数据。
不可重复读:一个事务中两次读取的数据的内容不一致。 事务 A 多次读取同一数据,事务 B 在事务 A 多次读取的过程中,对数据作了更新并提交,导致事务 A 多次读取同一数据时,结果 不一致。
幻读:一个事务中两次读取的数据量不一致。 系统管理员 A 将数据库中所有学生的成绩从具体分数改为 ABCDE 等级,但是系统管理员 B 就在这个时候插入了一条具体分数的记录,当系统管理员 A 改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。 解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。
6、事务的隔离级别有哪些?
串行化的隔离级别最高,读未提交的级别最低,级别越高,则执行效率就越低,所以在选择隔离级别时应该结合实际情况。
MySQL 支持以上四种隔离级别,默认为 Repeatable read (可重复读);而 Oracle 只支持 Serializeble(串行化) 级别和 Read committed(读已提交) 两种,其中默认为读已提交。
5 锁
1、数据库锁的作用以及有哪些锁?
当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制。即锁的作用是解决并发问题。
从锁的粒度划分,可以将锁分为表锁、行锁以及页锁。
行级锁:是锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。
行级锁开销大,加锁慢,且会出现死锁。但锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
表级锁:是粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。
页级锁:是粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折中的页级,一次锁定相邻的一组记录。
开销和加锁时间界于表锁和行锁之间,会出现死锁。锁定粒度界于表锁和行锁之间,并发度一般。
从使用性质划分,可以分为共享锁、排它锁以及更新锁。
共享锁(Share Lock):S 锁,又称读锁,用于所有的只读数据操作。
S 锁并非独占,允许多个并发事务对同一资源加锁,但加 S 锁的同时不允许加 X 锁,即资源不能被修改。S 锁通常读取结束后立即释放,无需等待事务结束。
排他锁(Exclusive Lock):X 锁,又称写锁,表示对数据进行写操作。
X 锁仅允许一个事务对同一资源加锁,且直到事务结束才释放,其他任何事务必须等到 X 锁被释放才能对该页进行访问。
使用 select * from table_name for update; 语句产生 X 锁。
更新锁:U 锁,用来预定要对资源施加 X 锁,允许其他事务读,但不允许再施加 U 锁或 X 锁。
当被读取的页将要被更新时,则升级为 X 锁,U 锁一直到事务结束时才能被释放。故 U 锁用来避免使用共享锁造成的死锁现象。
从主观上划分,又可以分为乐观锁和悲观锁。
乐观锁(Optimistic Lock):顾名思义,从主观上认定资源是不会被修改的,所以不加锁读取数据,仅当更新时用版本号机制等确认资源是否被修改。
乐观锁适用于多读的应用类型,可以系统提高吞吐量。
悲观锁(Pessimistic Lock):正如其名,具有强烈的独占和排它特性,每次读取数据时都会认为会被其它事务修改,所以每次操作都需要加上锁。
2、隔离级别和锁的关系?
1)在 Read Uncommitted 级别下,读取数据不需要加共享锁,这样就不会跟被修改的数据上的排他锁冲突;
2)在 Read Committed 级别下,读操作需要加共享锁,但是在语句执行完以后释放共享锁;
3)在 Repeatable Read 级别下,读操作需要加共享锁,但是在事务提交之前并不释放共享锁,也就是必须等待事务执行完毕以后才释放共享锁;
4)在 SERIALIZABLE 级别下,限制性最强,因为该级别锁定整个范围的键,并一直持有锁,直到事务完成。
3、InnoDB 中的锁算法?
Record lock:单个行记录上的锁
Gap lock:间隙锁,锁定一个范围,不包括记录本身
Next-key lock:record + gap 锁定一个范围,包含记录本身
5、什么是 MVCC 以及实现?
MVCC 的英文全称是 Multiversion Concurrency Control,中文意思是多版本并发控制,可以做到读写互相不阻塞,主要用于解决不可重复读和幻读问题时提高并发效率。
其原理是通过数据行的多个版本管理来实现数据库的并发控制,简单来说就是保存数据的历史版本。可以通过比较版本号决定数据是否显示出来。读取数据的时候不需要加锁可以保证事务的隔离效果。
1、什么是主从复制?
主从复制是用来建立一个与主数据库完全一样的数据库环境,即从数据库。主数据库一般是准实时的业务数据库。
2、主从复制的作用?
读写分离,使数据库能支撑更大的并发。
高可用,做数据的热备,作为后备数据库,主数据库服务器故障后,可切换到从数据库继续工作,避免数据丢失。
4、主从复制的实现原理?
数据库有个 binlog 二进制文件,记录了数据可执行的所有 SQL 语句。主从同步的目标就是把主数据库的 binlog 文件中的 SQL 语句复制到从数据库,让其在从数据的 relaylog 文件中再执行一次这些 SQL 语句即可。
具体实现需要三个线程:
binlog 输出线程:每当有从库连接到主库的时候,主库都会创建一个线程然后发送 binlog内 容到从库。
在从库里,当复制开始的时候,从库就会创建两个线程进行处理:
从库 IO 线程:当 START SLAVE 语句在从库开始执行之后,从库创建一个 IO 线程,该线程连接到主库并请求主库发送 binlog 里面的更新记录到从库上。从库 IO 线程读取主库的 binlog 输出线程发送的更新并拷贝这些更新到本地文件,其中包括 relaylog 文件。
从库 SQL 线程:从库创建一个 SQL 线程,这个线程读取从库 IO 线程写到 relaylog 的更新事件并执行。
ref MySQL主从复制面试之和原理
5、什么是异步复制和半同步?
MySQL 的主从复制有两种复制方式,分别是异步复制和半同步复制:
异步复制
MySQL 默认的主从复制方式就是异步复制,因为 Master 根本不考虑数据是否达到了 Slave,或 Slave 是否成功执行。
如过需要实现完全同步方式,即 Master 需要等待一个或所有 Slave 执行成功后才响应成功,那集群效率可想而知。故 MySQL 5.6 之后出现了一种折中的方式——半同步。
半同步复制
一主一从,一主多从情况下,Master 节点只要确认至少有一个 Slave 接受到了事务,即可向发起请求的客户端返回执行成功的操作。同时 Master 是不需要等待 Slave 成功执行完这个事务,Slave 节点接受到这个事务,并成功写入到本地 relay 日志中就算成功。
另外,在半同步复制时,如果主库的一个事务提交成功了,在推送到从库的过程当中,从库宕机了或网络故障,导致从库并没有接收到这个事务的Binlog,此时主库会等待一段时间(这个时间由rpl_semi_sync_master_timeout的毫秒数决定),如果这个时间过后还无法推送到从库,那 MySQL 会自动从半同步复制切换为异步复制,当从库恢复正常连接到主库后,主库又会自动切换回半同步复制。
半同步复制的“半”体现在,虽然主从库的Binlog是同步的,但主库不会等待从库执行完Relay-log后才返回,而是确认从库接收到Binlog,达到主从Binlog同步的目的后就返回了,所以从库的数据对于主库来说还是有延时的,这个延时就是从库执行Relay-log的时间。所以只能称为半同步。
6、主从中常见问题以及解决?
问题
1)主库宕机后,数据可能丢失。
2)从库只有一个sql Thread,主库写压力大,复制很可能延时。
解决
1)半同步复制:确保事务提交后 binlog 至少传输到一个从库 ,解决数据丢失的问题。
2)并行复制:从库多线程apply binlog,解决从库复制延迟的问题。
2、几种关联查询?
1) 内连接(自然连接):只返回匹配的行,如 Inner Join、Union Join。
2)外连接:返回一个表的全集,如 Left、Right、Full 和 Cross。
3、Where 和 Having 的区别?
where 子句的作用是在对查询结果进行分组前,将不符合条件的行去掉,即在分组之前过滤数据,where条件中不能包含聚组函数,使用where条件过滤出特定的行。
having 子句的作用是筛选满足条件的组,即在分组之后过滤数据,条件中经常包含聚组函数,使用having 条件过滤出特定的组,也可以使用多个分组标准进行分组。
总结一下条件的过滤顺序:on->join->where->group by->having。
5、In 和 Exists 的区别?
in 适合内表比外表数据小的情况,exists 适合内表比外表数据大的情况。如果查询的内外表大小相当,则二者效率差别不大。
6、Union 和 Union All 的区别?
Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序
Union All:对两个结果集进行并集操作,包括重复行,不进行排序
Union 因为要进行重复值扫描,所以效率低。如果合并没有刻意要删除重复行,那么就使用Union All。