前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >mysql系列-索引

mysql系列-索引

作者头像
用户6182664
发布2022-11-14 16:03:02
6350
发布2022-11-14 16:03:02
举报
文章被收录于专栏:Java程序员那些事

一 索引的基础

1.1 定义

索引是对数据库表中一列或多列的值进行排序的一种结构。本质上,是基于空间换时间的一种思路的实现。

常见的数据结构中, 哈希表和二叉平衡树的查找效率分别是O(1)和O(logn), 是效率最快的两个, MySQL也毫不意外的使用了这两种数据结构来做索引。 MySQL索引的数据结构有两种选择, B+Tree 和 Hash。

1.2 优点

1.2.1 提升检索效率
1、提高数据检索效率,降低数据库的IO成本;
2、降低数据排序成本,降低了CPU的消耗。

1.3 缺点

1.3.1 更新表速度降低
索引大大提高了查询速度,同时却降低更新表的速度。

MySQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的减值变化后的索引信息。

1.3.2 增加空间占用

索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也是要占用空间的。

1.4 生活中索引的应用

楼层索引
菜鸟驿站
图书目录索引

1.5 索引的分类

1.5.1 普通索引
1、语法
代码语言:javascript
复制
create index 索引名 on 表名 (字段名);
代码语言:javascript
复制

5.7版本InnoDB存储引擎,单表最大1017列,最多包含64个索引,联合索引最多16列。

https://dev.mysql.com/doc/refman/5.7/en/innodb-limits.html

代码语言:javascript
复制
CREATE TABLE `test_index` (  
    `c` bigint(16) NOT NULL AUTO_INCREMENT,  
    `c1` varchar(16) DEFAULT NULL,  
    `c2` varchar(16) DEFAULT NULL,  
    `c3` varchar(16) DEFAULT NULL,  
    `c4` varchar(16) DEFAULT NULL,  
    `c5` varchar(16) DEFAULT NULL,  
    `c6` varchar(16) DEFAULT NULL,  
    `c7` varchar(16) DEFAULT NULL,  
    `c8` varchar(16) DEFAULT NULL,  
    `c9` varchar(16) DEFAULT NULL,  
    `c10` varchar(16) DEFAULT NULL,  
    `c11` varchar(16) DEFAULT NULL,  
    `c12` varchar(16) DEFAULT NULL,  
    `c13` varchar(16) DEFAULT NULL,  
    `c14` varchar(16) DEFAULT NULL,  
    `c15` varchar(16) DEFAULT NULL,  
    `c16` varchar(16) DEFAULT NULL,  
    `c17` varchar(16) DEFAULT NULL,
  PRIMARY KEY (`c`),  KEY `idx_18` (`c1`,`c2`,`c3`,`c4`,`c5`,
  `c6`,`c7`,`c8`,`c9`,`c10`,`c11`,`c12`,`c13`,`c14`,`c15`,`c16`)
) ;
1.5.2 唯一索引
1、语法
代码语言:javascript
复制
create unique index 索引名 on 表名 (字段名)
代码语言:javascript
复制
2、场景

用户表,用户手机号码注册注册,手机号码创建唯一索引,重复手机号码新增,提示索引冲突。

1.5.3 组合索引

单个组合索引,mysql的5.7版本innodb引擎,允许最大设置16个列。

1、语法
代码语言:javascript
复制
create table 表名(
    字段名1 int(11) not null,
    字段名2 varchar(10) not null,    index(字段名1,字段名2)
);
代码语言:javascript
复制
2、最左匹配原则

在多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。

代码语言:javascript
复制
EXPLAIN SELECT *  FROM test_index WHERE c2='123';
代码语言:javascript
复制

1.6 索引创建规则

1.61 频繁作为查询条件的字段
适合查询频繁,修改较少的场景。
1.6.2 外键建立索引
表关联查询需求多,其他表的外键适合创建索引。
1.6.3 大文本字段
索引应该建在小字段上,对于大的文本字段甚至超长字段,不要建索引。
1.6.4 频繁更新
频繁进行数据操作的表,不要建立太多的索引。
1.6.5 重复值较多的列
性别字段主要就是“男”、“女”;职位字段中也是有限的几个内容。

添加索引也不会显著的增加查询速度,减少用户响应时间。 因为需要占用空间,反而会降低数据库的整体性能。

1.6.6 按范围查询的列,最好建立索引

索引已经排序,其保存的时候指定的范围是连续的,查询可以利用索引的排序,提高查询效率。 示例:年龄14到18的学生。

1.6.7 排序、统计

排序和统计的字段如果通过索引去访问,将大大提高排序速度。

1.6.8 索引不会包含有NULL值的列

只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。 建议:数据库设计时不要让字段的默认值为NULL。

二 索引的使用分析

代码语言:javascript
复制
CREATE TABLE `user_info` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `name` varchar(255) DEFAULT NULL,
    `nick` varchar(255) DEFAULT NULL,
    `sex` tinyint(2) DEFAULT NULL,
    `score` int(3) DEFAULT NULL,
    KEY `idx_id` (`id`),
    KEY `idx_score` (`score`) USING BTREE
);
代码语言:javascript
复制
insert into user_info values (1, '杨过', 'yangguo', '1', 90);
insert into user_info values (2, '小龙女', 'xiaolongnv', '0', 88);
insert into user_info values (3, '黄药师', 'huangyaoshi', '1', 75);
insert into user_info values (4, '郭襄', 'guoxiang', '0', 66);
insert into user_info values (5, '何足道', 'hezudao', '1', 50);
insert into user_info values (6, '独孤求败', 'duguqiubai', '1', 55);
insert into user_info values (7, '方东白', 'fangdongbai', '1', 88);
insert into user_info values (8, '赵敏', 'zhaomin', '0', 75);
insert into user_info values (9, '程灵素', 'chenglingsu','0', 66);

2.1 索引无效场景

2.1.1 字段取值 != 或者 <>
代码语言:javascript
复制
-- 使用了索引
EXPLAIN SELECT *  FROM user_info WHERE score = 55;    

-- 未使用索引
EXPLAIN SELECT *  FROM user_info WHERE score != 55;
代码语言:javascript
复制
2.1.2 字段列与查询数据列类型不一致

字符串未使用引号

代码语言:javascript
复制
  -- 使用了索引
  EXPLAIN SELECT *  FROM user_info WHERE sex = '0';    
  
  -- 未使用索引
  EXPLAIN SELECT *  FROM user_info WHERE sex = 0;
代码语言:javascript
复制
2.1.3 左模糊查询
代码语言:javascript
复制
EXPLAIN SELECT * FROM user_info WHERE score LIKE '5%';
代码语言:javascript
复制
2.1.4 or包含无索引字段
代码语言:javascript
复制
-- 使用了索引
EXPLAIN SELECT *  FROM user_info WHERE score = 55;    

-- 未使用索引
EXPLAIN SELECT * FROM user_info WHERE score = 55 OR nick='yangguo';
代码语言:javascript
复制
2.1.4 运算操作

相减,身份证截取,日期格式化,字符串拼接比较等。

代码语言:javascript
复制
-- 未使用索引
EXPLAIN SELECT * FROM user_info WHERE substr(name, 2, 2) = '灵素';
-- 使用了索引
EXPLAIN SELECT * FROM user_info WHERE name = '程灵素'; 

-- 使用了索引
EXPLAIN SELECT * FROM user_info WHERE score = 75;
-- 未使用索引
EXPLAIN SELECT * FROM user_info WHERE score-1 = 74;
代码语言:javascript
复制
2.1.5 IS NOT NULL
代码语言:javascript
复制
-- 使用索引
EXPLAIN SELECT *  FROM user_info WHERE score IS NULL;

-- 不使用索引
EXPLAIN SELECT *  FROM user_info WHERE score IS NOT NULL;
代码语言:javascript
复制

三 索引类型及原理

3.1 二叉树

3.1.1 左小

若左子树不空,则左子树上所有结点的值均小于它的根结点的值;

3.1.2 右大

若右子树不空,则右子树上所有结点的值均大于它的根结点的值;

3.1.3 跟节点居中

左、右子树也分别为二叉树

链表的查找时间复杂度是O(N),这时候最多需要7次才能查到所需数据。

3.1.4 时间复杂度

二叉搜索树查找数据的时间复杂度是O(logN),如图所示,最多查找3次就可以查到所需数据。

3.1.5 缺点

极端情况下,二叉查找树可能退化成线性链表 非平衡树,不适合做数据库索引。

代码语言:javascript
复制
代码实现:
https://gitee.com/ischenshuai/demo/tree/master/dataStruct/
tree/binary-tree-demo

3.2 B树

B树是有序数组+平衡多叉树,总体有序。 树的高度越高,查找次数越多,也就是磁盘IO次数越多,耗时越长。 降低树的高度,把二叉树变成N叉树,即B树

3.2.1 m阶的B树
1、根节点至少有2个子节点
2、每个中间节点都包含k-1个元素和k个子节点,其中 m/2 <= k <= m
3、每个叶子节点都包含k-1个元素,其中 m/2 <= k <= m
4、中间节点的元素按照升序排列
5、所有的叶子结点都位于同一层
3.2.2 树分析
1. 根节点(8)有两个子节点,左子节点(3 5)和右子节点(11 15)。
2. 左子节点(3 5)中有2个元素和3个子节点。
3. 元素是3和5,按照升序排列。
4. 子节点是(1 2)、(4)、(6 7),
5. 而(1 2)中元素小于3,(4)中的元素在3和5中间,(6 7)的元素大于5,符合B树特征。
3.2.3 优点

高度更低,每个节点含有多个元素,查找的时候一次可以把一个节点中的所有元素加载到内存中作比较,两种改进都大大减少了磁盘IO次数。

3.3 红黑树

3.3.1 定义
1、节点要求

节点必须是红色或者黑色

2、根节点要求

根节点必须是黑色

3、叶子节点要求

叶子节点全部为黑色,叶子是NIL结点

4、红节点要求

每个红色结点的两个子结点都是黑色(从每个叶子到根的所有路径上不能有两个连续的红色结点)

5、节点路径要求

从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点

3.3.2 红黑树目标要求
1、优点

限制了左右子树的树高,不会相差过大。查询效率高

2、缺点

规则复杂,可能红黑树转化,开销大

3.4 B+ Tree

有序数组链表+平衡多叉树

3.4.1 约定
1、有k个子节点的中间节点就有k个元素(B树中是k-1个元素),也就是子节点数量 = 元素数量。每个元素不保存数据,只用来索引,所有数据都保存在叶子节点上。
2、所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。
3、非叶子节点只保存索引,不保存数据。(B树中两者都保存)。
4、叶子结点包含了全部元素的信息,并且叶子结点按照元素大小组成有序列表。
3.4.2 优点
1、每个节点存储的元素更多,看起来比B树更矮胖,导致磁盘IO次数更少。
2、非叶子节点不存储数据,只存储索引,叶子节点存储全部数据。这样设计导致每次查找都会查到叶子节点,效率更稳定,便于做性能优化。
3、叶子节点之间使用有序链表连接。这样设计方便范围查找,只需要遍历链表中相邻元素即可,不再需要二次遍历二叉树。

3.5 hash

3.5.1 hash冲突

将车库中的车牌号按简称排列,重复的简称,可成为hash冲突。 多个不同的值通过算出了同一个hash值被称之为hash冲突。

3.5.2 hash索引使用场景
1、对等比较

等值比较,使用hash索引效率更高。 由于是一次定位数据,不像BTree索引需要从根节点到枝节点,最后才能访问到页节点这样多次IO访问,所以检索效率远高于BTree索引。

3.5.3 hash索引缺点
1、Hash 索引不能进行范围查询

Hash 索引指向的数据是无序的,而 B+ 树的叶子节点是个有序的链表。

2、Hash 索引不支持联合索引的最左侧原则

对于联合索引来说,Hash 索引在计算 Hash 值的时候是将索引键合并后再一起计算 Hash 值,所以不会针对每个索引单独计算 Hash 值。因此如果用到联合索引的一个或者几个索引时,联合索引无法被利用。

3、Hash 索引不支持 ORDER BY 排序

Hash 索引指向的数据是无序的,因此无法起到排序优化的作用,而 B+ 树索引数据是有序的,可以起到对该字段 ORDER BY 排序优化的作用。

4、无法模糊查询

B+ 树使用 LIKE 进行模糊查询的时候,LIKE 后模糊查询的话就可以起到优化作用。

对于等值查询来说,通常 Hash 索引的效率更高,但是,索引列的重复值如果很多,效率就会降低。这是因为遇到 Hash 冲突时,需要遍历桶中的行指针来进行比较,找到查询的关键字,非常耗时。所以,Hash 索引通常不会用到重复值多的列上,比如列为性别、年龄的情况等。

三 索引相关的问题

3.1 锁表问题

3.1.1 更新时锁表
1、使用非索引字段更新,导致锁表。

在 update 语句的 where 条件没有使用索引,就会全表扫描。 使用索引后,使用“行锁”进行udpate,只锁当前行。不影响其他行的查询更新

3.2 不当索引导致性能开销

使用性别等字段,导致数据查询效果性能提升不大,且增加修改成本。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-08-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java程序员那些事 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一 索引的基础
    • 1.1 定义
      • 1.2 优点
        • 1.2.1 提升检索效率
      • 1.3 缺点
        • 1.3.1 更新表速度降低
        • 1.3.2 增加空间占用
      • 1.4 生活中索引的应用
        • 1.5 索引的分类
          • 1.5.1 普通索引
          • 1.5.2 唯一索引
          • 1.5.3 组合索引
        • 1.6 索引创建规则
          • 1.61 频繁作为查询条件的字段
          • 1.6.2 外键建立索引
          • 1.6.3 大文本字段
          • 1.6.4 频繁更新
          • 1.6.5 重复值较多的列
          • 1.6.6 按范围查询的列,最好建立索引
          • 1.6.7 排序、统计
          • 1.6.8 索引不会包含有NULL值的列
      • 二 索引的使用分析
        • 2.1 索引无效场景
          • 2.1.1 字段取值 != 或者 <>
          • 2.1.2 字段列与查询数据列类型不一致
          • 2.1.3 左模糊查询
          • 2.1.4 or包含无索引字段
          • 2.1.4 运算操作
          • 2.1.5 IS NOT NULL
      • 三 索引类型及原理
        • 3.1 二叉树
          • 3.1.1 左小
          • 3.1.2 右大
          • 3.1.3 跟节点居中
          • 3.1.4 时间复杂度
          • 3.1.5 缺点
        • 3.2 B树
          • 3.2.1 m阶的B树
          • 3.2.2 树分析
          • 3.2.3 优点
        • 3.3 红黑树
          • 3.3.1 定义
          • 3.3.2 红黑树目标要求
        • 3.4 B+ Tree
          • 3.4.1 约定
          • 3.4.2 优点
        • 3.5 hash
          • 3.5.1 hash冲突
          • 3.5.2 hash索引使用场景
          • 3.5.3 hash索引缺点
      • 三 索引相关的问题
        • 3.1 锁表问题
          • 3.1.1 更新时锁表
        • 3.2 不当索引导致性能开销
        相关产品与服务
        对象存储
        对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档