写点什么

MySQL 存储引擎及索引简介

  • 2024-12-18
    北京
  • 本文字数:4552 字

    阅读完需:约 15 分钟

作者:京东物流 樊芳渝

一、引言

在信息技术飞速发展的今天,数据库作为信息系统的核心组件,其性能和稳定性直接关系到整个系统的运行效率和用户体验。而 MySQL,作为目前最流行的开源关系型数据库管理系统之一,凭借其强大的功能、灵活的扩展性和广泛的应用场景,早已成为众多开发者和企业的首选。


然而,要想充分发挥 MySQL 的性能优势,深入了解其存储引擎和索引机制是必不可少的。存储引擎决定了 MySQL 如何存储、处理和检索数据,不同的存储引擎在事务处理、数据完整性、并发控制等方面有着不同的特点和优势。而索引,则是 MySQL 高效查询的关键所在,它能够帮助数据库系统快速定位到所需的数据,极大地提高查询效率。

二、存储引擎

MySQL 体系结构



存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式。存储引擎是基于表而不是基于库的,所以存储引擎也可以被称为表引擎。 默认存储引擎是 InnoDB。


相关操作:


-- 查询建表语句show create table account;-- 建表时指定存储引擎CREATE TABLE 表名(    ...) ENGINE=INNODB;-- 查看当前数据库支持的存储引擎show engines;
复制代码

InnoDB

InnoDB 是一种兼顾高可靠性和高性能的通用存储引擎,在 MySQL 5.5 之后,InnoDB 是默认的 MySQL 引擎。


特点:


•DML 操作遵循 ACID 模型,支持事务


行级锁,提高并发访问性能


•支持外键约束,保证数据的完整性和正确性


知识点:


查看 Mysql 变量:


show variables like 'innodb_file_per_table';
复制代码


InnoDB 逻辑存储结构:


三、索引

索引概述

索引是帮助 MySQL 高效获取数据数据结构(有序) 。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查询算法,这种数据结构就是索引。


优缺点:


优点:


•提高数据检索效率,降低数据库的 IO 成本


•通过索引列对数据进行排序,降低数据排序的成本,降低 CPU 的消耗


缺点:


•索引列也是要占用空间的


•索引大大提高了查询效率,但降低了更新的速度,比如 INSERT、UPDATE、DELETE

索引结构

B-Tree


二叉树的缺点可以用红黑树来解决:



红黑树也存在大数据量情况下,层级较深,检索速度慢的问题。


为了解决上述问题,可以使用 B-Tree 结构。 B-Tree (多路平衡查找树) 以一棵最大度数(max-degree,指一个节点的子节点个数)为 5(5 阶)的 b-tree 为例(每个节点最多存储 4 个 key,5 个指针) 演示地址:https://www.cs.usfca.edu/~galles/visualization/BTree.html



树的度数是指一个节点的子节点个数。

B+Tree

结构图:



与 B-Tree 的区别:


•所有的数据都会出现在叶子节点


•叶子节点形成一个单向链表


MySQL 索引数据结构对经典的 B+Tree 进行了优化。在原 B+Tree 的基础上,增加一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的 B+Tree,提高区间访问的性能。


索引分类


在 InnoDB 存储引擎中,根据索引的存储形式,又可以分为以下两种:



聚集索引选取规则:


•如果存在主键,主键索引就是聚集索引


•如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引


•如果表没有主键或没有合适的唯一索引,则 InnoDB 会自动生成一个 rowid 作为隐藏的聚集索引

索引语法

创建索引:


CREATE [ UNIQUE | FULLTEXT ] INDEX index_name ON table_name (index_col_name, ...);
复制代码


查看索引:


SHOW INDEX FROM table_name;
复制代码


删除索引:


DROP INDEX index_name ON table_name;
复制代码

SQL 性能分析

查看执行频次

查看当前数据库的 INSERT, UPDATE, DELETE, SELECT 访问频次:


SHOW GLOBAL STATUS LIKE 'Com_______';
复制代码

慢查询日志

慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认 10 秒)的所有 SQL 语句的日志。 MySQL 的慢查询日志默认没有开启,需要在 MySQL 的配置文件(/etc/my.cnf)中配置如下信息:


# 开启慢查询日志开关slow_query_log=1# 设置慢查询日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志long_query_time=2
复制代码


更改后记得重启 MySQL 服务,日志文件位置:/var/lib/mysql/localhost-slow.log


查看慢查询日志开关状态:


show variables like 'slow_query_log';
复制代码

profile

show profile 能在做 SQL 优化时帮我们了解时间都耗费在哪里。通过 have_profiling 参数,能看到当前 MySQL 是否支持 profile 操作:


SELECT @@have_profiling;
复制代码


profiling 默认关闭,可以通过 set 语句在 session/global 级别开启 profiling:


SET profiling = 1;
复制代码


查看所有语句的耗时:


show profiles;
复制代码


查看指定 query_id 的 SQL 语句各个阶段的耗时:


show profile for query query_id;
复制代码


查看指定 query_id 的 SQL 语句 CPU 的使用情况


show profile cpu for query query_id;
复制代码

explain

EXPLAIN 或者 DESC 命令获取 MySQL 如何执行 SELECT 语句的信息,包括在 SELECT 语句执行过程中表如何连接和连接的顺序。 语法:


# 直接在select语句之前加上关键字 explain / descEXPLAIN SELECT 字段列表 FROM 表名 HWERE 条件;
复制代码


EXPLAIN 各字段含义:


•id:select 查询的序列号,表示查询中执行 select 子句或者操作表的顺序(id 相同,执行顺序从上到下;id 不同,值越大越先执行)


•select_type:表示 SELECT 的类型,常见取值有 SIMPLE(简单表,即不适用表连接或者子查询)、PRIMARY(主查询,即外层的查询)、UNION(UNION 中的第二个或者后面的查询语句)、SUBQUERY(SELECT/WHERE 之后包含了子查询)等


•type:表示连接类型,性能由好到差的连接类型为 NULL、system、const、eq_ref、ref、range、index、all


•possible_key:可能应用在这张表上的索引,一个或多个


•Key:实际使用的索引,如果为 NULL,则没有使用索引


•Key_len:表示索引中使用的字节数,该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下,长度越短越好


•rows:MySQL 认为必须要执行的行数,在 InnoDB 引擎的表中,是一个估计值,可能并不总是准确的


•filtered:表示返回结果的行数占需读取行数的百分比,filtered 的值越大越好

索引使用

最左前缀法则

•如果索引关联了多列(联合索引),要遵守最左前缀法则,最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。


•如果跳跃某一列,索引将部分失效(后面的字段索引失效)。


•联合索引中,出现范围查询(<, >),范围查询右侧的列索引失效。可以用>=或者<=来规避索引失效问题。

索引失效情况

1.在索引列上进行运算操作,索引将失效。如:


explain select * from tb_user where substring(phone, 10, 2) = '15';
复制代码


1.字符串类型字段使用时,不加引号,索引将失效。如:


explain select * from tb_user where phone = 17799990015;
复制代码


此处 phone 的值没有加引号


1.模糊查询中,如果仅仅是尾部模糊匹配,索引不会是失效;如果是头部模糊匹配,索引失效。如:


explain select * from tb_user where profession like '%工程';
复制代码


前后都有 % 也会失效。


1.用 or 分割开的条件,如果 or 其中一个条件的列没有索引,那么涉及的索引都不会被用到。


2.如果 MySQL 评估使用索引比全表更慢,则不使用索引。

SQL 提示

是优化数据库的一个重要手段,简单来说,就是在 SQL 语句中加入一些人为的提示来达到优化操作的目的。


例如,使用索引:


explain select * from tb_user use index(idx_user_pro) where profession="软件工程";
复制代码


不使用哪个索引:


explain select * from tb_user ignore index(idx_user_pro) where profession="软件工程";
复制代码


必须使用哪个索引:


explain select * from tb_user force index(idx_user_pro) where profession="软件工程";
复制代码


use 是建议,实际使用哪个索引 MySQL 还会自己权衡运行速度去更改,force 就是无论如何都强制使用该索引。

前缀索引

当字段类型为字符串(varchar, text 等)时,有时候需要索引很长的字符串,这会让索引变得很大,查询时,浪费大量的磁盘 IO,影响查询效率,此时可以只降字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率。


语法:


create index idx_xxxx on table_name(columnn(n));
复制代码


前缀长度:可以根据索引的选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值,索引选择性越高则查询效率越高,唯一索引的选择性是 1,这是最好的索引选择性,性能也是最好的。 求选择性公式:


select count(distinct email) / count(*) from tb_user;select count(distinct substring(email, 1, 5)) / count(*) from tb_user;
复制代码


show index 里面的 sub_part 可以看到接取的长度

单列索引 &联合索引

单列索引:即一个索引只包含单个列 联合索引:即一个索引包含了多个列 在业务场景中,如果存在多个查询条件,考虑针对于查询字段建立索引时,建议建立联合索引,而非单列索引。


单列索引情况:


explain select id, phone, name from tb_user where phone = '17799990010' and name = '韩信';
复制代码


这句只会用到 phone 索引字段

注意事项

•多条件联合查询时,MySQL 优化器会评估哪个字段的索引效率更高,会选择该索引完成本次查询

设计原则

1.针对于数据量较大,且查询比较频繁的表建立索引


2.针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引


3.尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高


4.如果是字符串类型的字段,字段长度较长,可以针对于字段的特点,建立前缀索引


5.尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率


6.要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价就越大,会影响增删改的效率


7.如果索引列不能存储 NULL 值,请在创建表时使用 NOT NULL 约束它。当优化器知道每列是否包含 NULL 值时,它可以更好地确定哪个索引最有效地用于查询

四、总结

首先,我们了解到 MySQL 支持多种存储引擎,每种存储引擎都有其独特的特点和适用场景。例如,InnoDB 是 MySQL 的默认存储引擎,它提供了事务支持、行级锁定和外键约束等功能,非常适合需要高可靠性和并发控制的应用场景。而 MyISAM 则以其快速的读操作和全文索引支持而闻名,但在事务处理和行级锁定方面相对较弱。此外,还有其他存储引擎如 Memory、CSV 等,它们各自在不同的应用场景中发挥着重要作用。


其次,我们深入了解了索引在 MySQL 中的重要性。索引是数据库系统高效查询的关键所在,它能够帮助数据库系统快速定位到所需的数据,极大地提高查询效率。我们探讨了 MySQL 中的几种主要索引类型,包括 B 树索引、哈希索引、全文索引等,并了解了它们的工作原理和适用场景。同时,我们也强调了索引的创建和维护需要谨慎进行,以避免对数据库性能产生负面影响。


最后,我们强调了在实际应用中需要根据具体需求选择合适的存储引擎和索引策略。不同的应用场景对数据库的性能、可靠性、可扩展性等方面有着不同的要求,因此我们需要根据实际需求进行权衡和选择。同时,我们也提到了 MySQL 在存储引擎和索引方面的不断发展和创新,如 InnoDB 的持续优化和新的索引类型的引入等,这些都为我们提供了更多的选择和可能性。


总之,通过今天的分享,我们对 MySQL 的存储引擎及索引有了更深入的认识和理解。希望这些知识能够帮助我们在实际应用中更加得心应手地处理数据库相关的问题和挑战。同时,我也鼓励大家继续深入学习和探索 MySQL 的更多高级特性和优化技巧,以不断提升我们的数据库管理和应用能力。

发布于: 刚刚阅读数: 4
用户头像

拥抱技术,与开发者携手创造未来! 2018-11-20 加入

我们将持续为人工智能、大数据、云计算、物联网等相关领域的开发者,提供技术干货、行业技术内容、技术落地实践等文章内容。京东云开发者社区官方网站【https://developer.jdcloud.com/】,欢迎大家来玩

评论

发布
暂无评论
MySQL存储引擎及索引简介_京东科技开发者_InfoQ写作社区