MySql索引原理与操作

 更新时间:2022年09月16日 11:29:02   作者:在人间负债^  
索引是有双面性的,合理的建立索引可以提高数据库的效率。但是如果没有合理的构建索引和使用索引,可能会导致索引失效或者影响数据库性能,这篇文章主要介绍了MySql索引原理与操作

1. 什么是索引

索引是在数据库表的字段上添加的,是为了提高查询效率存在的一种机制。

一张表的一个字段可以添加一个索引,当然,多个字段联合起来也可以添加索引。

索引相当于一本书的目录,是为了缩小扫描范围而存在的一种机制。

索引相当于一本书的目录

通过索引查询的方式被称为索引查询。

在 mysql 数据库当索引也是需要排序的,并且这个索引的排序和 TreeSet 数据结构相同。TreeSet(TreeMap)底层是一个自平衡二叉树!在 mysql 当中索引是一个 B-Tree 数据结构。

遵循左小右大原则存放。采用中序遍历方式遍历取数据。

2. 索引的实现原理

提醒:

在任何数据库中主键上都会自动添加索引对象,id 字段上自动有索引,因为 id 是主键。另外在 mysql 中,如果一个字段有 unique 约束的话,也会自动创建索引对象。

任何数据库中,然后一张表的任何一条记录在硬盘存储上都有一个硬盘的物理存储编号。在 mysql 中,索引是一个单独的对象,在不同的存储引擎以不同的形式存在,

在 MyISAM 存储引擎中,索引存储在一个 .MYI 文件中。在 InnoDB 存储引擎中,索引存储在一个逻辑名叫做 tablespace 的当中。在 MEMORY 存储引擎中,索引存储在内存中。不管索引存储在哪里,索引在 mysql 中都是一个树的形式存在。

3. 添加索引的条件

  • 数据量庞大(具体多么庞大算庞大,这个需要测试,因为每一个硬件环境不同)
  • 该字段经常出现在 where 的后面,以条件的形式存在,也就是说这个字段总是被扫描。
  • 该字段很少的 DML(insert、delete、update)操作。(因为 DML 之后,索引需要重新排序)

建议不要随意添加索引,因为索引也是需要维护的,太多的话反而会降低系统的性能。

建议通过主键查询,建议通过 unique 约束的字段进行查询,效率是比较高的。

4. 索引的操作

1. 创建索引

给 emp 表的 ename 字段添加索引,起名:emp_ename_index

mysql> create index emp_ename_index on emp(ename);

2. 删除索引

将 emp 表上的 emp_ename_index 索引对象删除

mysql> drop index emp_ename_index on emp;

3. 查看一个sql语句是否使用了索引进行检索

mysql> explain select * from emp where ename = 'KING';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | emp   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   14 |    10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.01 sec)

扫描14条记录:说明没有使用索引。type = ALL

mysql> create index emp_ename_index on emp(ename);
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> explain select * from emp where ename = 'KING';
+----+-------------+-------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys   | key             | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | emp   | NULL       | ref  | emp_ename_index | emp_ename_index | 43      | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

5. 索引的失效

失效的第1种情况:

mysql> select * from emp where ename like '%T';

ename 上即使添加了索引,也不会走索引进行查询,为什么?

因为模糊查询匹配中以 “%” 开头了。

尽量避免模糊查询的时候以 “%” 开始。

这是一种优化的手段。

mysql> explain select * from emp where ename like '%T';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | emp   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   14 |    11.11 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.01 sec)

失效的第2种情况:

使用 or 的时候会失效,如果使用 or 那么要求 or 两边的条件字段都要有索引,才会进行索引查询,如果其中一边有一个字段没有索引,那么另一个字段上的索引也会实现。索引这就是为什么不建议使用 or 的原因。

mysql> explain select * from emp where ename = 'KING' or job = 'MANAGER';
+----+-------------+-------+------------+------+-----------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys   | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+-----------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | emp   | NULL       | ALL  | emp_ename_index | NULL | NULL    | NULL |   14 |    16.43 | Using where |
+----+-------------+-------+------------+------+-----------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

失效的第3种情况:

使用复合索引的时候,没有使用左侧的列查找,索引失效。

什么是复合索引?

两个字段,或者更多的字段联合起来添加一个索引,叫做复合索引。

mysql> explain select * from emp where job = 'MANAGER';
+----+-------------+-------+------------+------+-------------------+-------------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys     | key               | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+-------------------+-------------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | emp   | NULL       | ref  | emp_job_sal_index | emp_job_sal_index | 39      | const |    3 |   100.00 | NULL  |
+----+-------------+-------+------------+------+-------------------+-------------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select * from emp where sal = 800;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | emp   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   14 |    10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

失效的第4种情况:

在 where 中索引列参加了运算,索引失效。

mysql> create index emp_sal_index on emp(sal);
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> explain select * from emp where sal = 800;
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key           | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | emp   | NULL       | ref  | emp_sal_index | emp_sal_index | 9       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select * from emp where sal + 1 = 800;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | emp   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   14 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.01 sec)

失效的第5种情况:

在 where 中索引列使用了函数

mysql> explain select * from emp where lower(ename) = 'smith';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | emp   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   14 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.01 sec)

6. 索引的类型

  1. 单一索引:一个字段上添加索引
  2. 复合索引:两个或多个字段上添加索引
  3. 主键索引:主键上添加索引
  4. 唯一性索引:具有 unique 约束的字段上添加索引

注意: 唯一性比较弱的字段上添加索引用处不大。

相对来说,唯一性越高,效率越高。

到此这篇关于MySql索引原理与操作的文章就介绍到这了,更多相关MySql索引内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MySQL无服务及服务无法启动的终极解决方案分享

    MySQL无服务及服务无法启动的终极解决方案分享

    又是MySQL的问题,之前已经遇见过一次本地MySQL服务无法启动的情况,现在又出现了,下面这篇文章主要给大家介绍了关于MySQL无服务及服务无法启动的终极解决方案,需要的朋友可以参考下
    2022-06-06
  • MySQL之select、distinct、limit的使用

    MySQL之select、distinct、limit的使用

    这篇文章主要介绍了MySQL之select、distinct、limit的使用,下面文章围绕select、distinct、limit的相关资料展开聚集内容,需要的朋友可以参考一下
    2021-11-11
  • Mysql修改字段类型、长度及添加删除列实例代码

    Mysql修改字段类型、长度及添加删除列实例代码

    在MySQL中可以使用ALTER TABLE语句来修改表结构,包括添加自增属性,下面这篇文章主要给大家介绍了关于Mysql修改字段类型、长度及添加删除列的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-04-04
  • MYSQL插入处理重复键值的几种方法

    MYSQL插入处理重复键值的几种方法

    当unique列在一个UNIQUE键上插入包含重复值的记录时,默认insert的时候会报1062错误,MYSQL有三种不同的处理方法,下面我们分别介绍。
    2012-09-09
  • Mysql InnoDB B+树索引目录项记录页管理

    Mysql InnoDB B+树索引目录项记录页管理

    这篇文章主要为大家介绍了Mysql InnoDB B+树索引目录项记录页管理,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • VS2019连接mysql8.0数据库的教程图文详解

    VS2019连接mysql8.0数据库的教程图文详解

    这篇文章主要介绍了VS2019连接mysql8.0数据库的教程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-05-05
  • 如何使用MySQL查询一年中每月的记录数

    如何使用MySQL查询一年中每月的记录数

    这篇文章主要给大家介绍了关于如何使用MySQL查询一年中每月的记录数的相关资料,文中通过实例代码以及图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-09-09
  • Mysql事物阻塞的实现

    Mysql事物阻塞的实现

    本文主要介绍了Mysql事物阻塞的实现,阻塞并不是一件坏事,其是为了确保事务可以并发且正常地运行,具有一定的参考价值,感兴趣的可以了解一下
    2024-04-04
  • SQL中distinct去重关键字使用和count统计组合使用方法

    SQL中distinct去重关键字使用和count统计组合使用方法

    这篇文章主要给大家介绍了关于SQL中distinct去重关键字使用和count统计组合使用的相关资料,count()是SQL中提供的用于统计记录数量的函数,需要的朋友可以参考下
    2024-08-08
  • MySQL使用binlog日志做数据恢复的实现

    MySQL使用binlog日志做数据恢复的实现

    这篇文章主要介绍了MySQL使用binlog日志做数据恢复的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03

最新评论