MySQL之索引
一、索引的本质
索引(Index):排好序的,能够快速查找数据的数据结构,能够帮助 MySQL 高效获取数据。
索引的本质:索引是数据结构。你可以简单理解为“排好序的快速查找数据结构”,满足特定查找算法。 这些数据结构以某种方式指向数据, 这样就可以在这些数据结构的基础上实现 高级查找算法 。
一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。
索引如果没有特别指明,都是指B-Tree(多路搜索树,并不一定是二叉树)结构组织的索引。
其中聚集索引,次要索引,覆盖索引,复合索引,前缀索引,唯一索引默认都是使用B+树索引。
除了B+树索引,还有哈希索引。
二、索引的优势和劣势
优势:
- 提高数据检索的效率,降低磁盘IO成本
- 数据分组、排序:减少查询中分组和排序的时间、降低CPU消耗
- 通过创建唯一索引,可以保证数据库表中每一行 数据的唯一性
- 在实现数据的 参考完整性方面,可以加速表和表之间的连接
劣势:
- 索引本质也是一张表,保存着索引字段和指向实际记录的指针,所以也要占用数据库空间,一般而言,索引表占用的空间是数据表的1.5倍
- 索引虽然能提高查询速度,但是会降低表的更新速度,因为更新数据时,也要更新索引
- 创建索引和维护索引要 耗费时间 ,并 且随着数据量的增加,所耗费的时间也会增加
特别说明:索引可以提高查询的速度,但是会影响插入记录的速度,这种情况,先删除索引,然后插入数据,数据插入完成后再创建索引
三、索引的分类
常见的索引类型有:主键索引、唯一索引、普通索引、全文索引、组合索引等
创建索引
主键索引:根据主键建立的索引,不允许重复,不允许空值 ALTER TABLE [table_name] ADD PRIMARY KEY pk_index('col'); 唯一索引: 用来建立索引的列的值必须是唯一的,允许空值 ALTER TABLE [table_name] ADD UNIQUE index_name([colum]); 普通索引:用表中的普通列构建的索引,没有任何限制 ALTER TABLE [table_name] ADD INDEX idx_[table_name]_index_name([colum]); 全文索引:用大文本对象的列构建的索引 ALTER TABLE [table_name] ADD FULLTEXT INDEX ft_index([colum]); 组合索引:用多个列组合构建的索引,这多个列中的值不允许有空值 ALTER TABLE [table_name] ADD INDEX index_name([colum1],[colum2],[colum3]); 查看索引 SHOW INDEX FROM 'table_name' 删除索引 DROP INDEX index_name ON 'table_name'1
四、索引创建的条件
创建索引:
- 主键自动建立唯一索引
- 字段的数值有唯一性的限制
- 频繁作为where查询条件的字段应该创建索引
- 与其他表关联的字段,外键关系应该创建索引
- 查询中排序的字段
- 查询中统计的字段或者分组字段
- 经常group by 和order by的列
- update\delete的where条件列表
- distinct字段需要创建索引
- 使用列的类型小的创建索引
- 使用字符串签字创建索引
- 区分度高(散列性高的列适合作为索引)
- 使用最频繁的列放到联合索引的左侧
- 在多个字段都要创建索引的情况下,联合索引优于单值索引
补充:
1、联合索引由于单值索引
2、多表 JOIN 连接操作时,创建索引注意事项
- 连接表的数量尽量不要超过 3 张
- 对 WHERE 条件创建索引
- 对用于连接的字段创建索引(类型必须一致)
无需创建索引:
- 数据量少的表不需要创建索引
- 频繁更新的字段、表(如果创建索引,每当更新字段都会更新索引)
- 数据重复且分布平均的字段,不宜创建索引(性别字段,国籍字段等)
- 在where中使用不到的字段,不要设置索引
- 不建议无序的值作为索引
- 不要定义冗余或重复的所有
补充:当数据量重复度大,比例高于10%的时候,也不需要对这个字段使用索引
索引失效:
- 全值匹配我最爱
- 最佳左前缀法则(索引文件具有 B-Tree 的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引。)
- 主键插入顺序(我们自定义的主键列 id 拥有 AUTO_INCREMENT 属性,在插入记录时存储引擎会自动为我们填入自增的主键值。这样的主键占用空间小,顺序写入,减少页分裂。)
- 计算、函数、类型转换(自动或手动)导致索引失效
- 类型转换导致索引失效
- 范围条件右边的列索引失效(如:WHERE student.age=30 AND student.classId>20 AND student.name = 'abc',按顺序创建联合索引,name字段索引会失效,正确索引是将范围查询条件放置语句最后:create index idx_age_name_classid on student(age,name,classid);)
- 不等于(!= 或者<>)索引失效
- like以通配符%开头索引失效(【强制】页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。)
- OR 前后存在非索引的列,索引失效
- 数据库和表的字符集统一使用utf8mb4(统一使用utf8mb4( 5.5.3版本以上支持)兼容性更好,统一字符集可以避免由于字符集转换产生的乱码。不同的 字符集 进行比较前需要进行 转换 会造成索引失效。)
- 8 is null可以使用索引,is not null无法使用索引
五、B+Tree 与 B-Tree 的区别
- B-树的关键字和记录是放在一起的,叶子节点可以看作外部节点,不包含任何信息;B+树的所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,非叶子节点中只存有关键字和指向下一个节点的索引,这样可以大大加大每个节点存储的key值数量,降低B+Tree的高度。
- 在 B-树中,越靠近根节点的记录查找时间越快,只要找到关键字即可确定记录的存在
- B+树中每个记录 的查找时间基本相同,都需要从根节点走到叶子节点,而且在叶子节点中还要再比较关键字。从这个角度看 B- 树的性能好像要比 B+树好,而在实际应用中却是 B+树的性能要好些。因为 B+树的非叶子节点不存放实际的数据, 这样每个节点可容纳的元素个数比 B-树多,树高比 B-树小,这样带来的好处是减少磁盘访问次数。尽管 B+树找到 一个记录所需的比较次数要比 B-树多,但是一次磁盘访问的时间相当于成百上千次内存比较的时间,因此实际中 B+树的性能可能还会好些,而且 B+树的叶子节点使用指针连接在一起,方便顺序遍历(例如查看一个目录下的所有 文件,一个表中的所有记录等),这也是很多数据库和文件系统使用 B+树的缘故。
B+Tree的优势:
- B+树的磁盘读写代价更低
- B+树的内部结点并没有指向关键字具体信息的指针。因此其内部结点相对 B 树更小。如果把所有同一内部结点 的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就 越多。相对来说 IO 读写次数也就降低了
- B+树的查询效率更加稳定,由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须 走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。
B树:
B+树:
六、聚簇索引和非聚簇索引
聚簇索引:
- 并不是一种单独的索引类型,而是一种数据存储方式,
- 索引顺序就是数据的物理存储顺序
- 聚集索引一个表只能有一个
聚簇索引的好处:
- 按照聚簇索引排列顺序,查询显示一定范围数据的时候,由于数据都是紧密相连,数据库不用从多 个数据块中提取数据,所以节省了大量的 io 操作。
聚簇索引的限制:
- 对于 mysql 数据库目前只有 innodb 数据引擎支持聚簇索引,而 Myisam 并不支持聚簇索引。 由于数据物理存储排序方式只能有一种,所以每个 Mysql 的表只能有一个聚簇索引。一般情况下就是 该表的主键。 为了充分利用聚簇索引的聚簇的特性,所以 innodb 表的主键列尽量选用有序的顺序 id,而不建议用 无序的 id,比如 uuid。
- 如果没有定义主键,innodb会选择非空的唯一索引代替。如果没有这样的索引,innodb会隐式的定义一个主键来作为聚簇索引。
非聚簇索引:
- 又叫二级索引。二级索引的叶子节点中保存的不是指向行的物理指针,而是行的主键值。当通过二级索引查找行,存储引擎需要在二级索引中找到相应的叶子节点,获得行的主键值,然后使用主键去聚簇索引中查找数据行,这需要两次B-Tree查找。
- MyISAM引擎来说,是按照非聚簇索引的形式存储数据:
- 非聚集索引一个表可以存在多个
- 非聚集索引是逻辑上的连续,物理存储并不连续,物理存储不按照索引排序。
- 索引顺序与数据物理排列顺序无关
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性