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千万不要这样写update语句

    MySQL千万不要这样写update语句

    MySQL中update语句用于更新表中的现有数据,亦可用UPDATE语句来更改表中单个行,一组行或所有行的列值,这篇文章主要给大家介绍了关于MySQL千万不要这样写update语句的相关资料,需要的朋友可以参考下
    2021-11-11
  • 透彻理解Mysql连接的原理

    透彻理解Mysql连接的原理

    这篇文章主要为大家介绍了Mysql连接原理的深入理解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • MySQL数据库恢复(使用mysqlbinlog命令)

    MySQL数据库恢复(使用mysqlbinlog命令)

    binlog是通过记录二进制文件方式来备份数据,然后在从二进制文件将数据恢复到某一时段或某一操作点。
    2011-08-08
  • 解决mysql的赋权操作之GRANT ALL PRIVILEGES ON *.* TO ‘root‘@‘%‘ IDENTIFIED BY ‘123456‘ WITH GRANT OPTION问题

    解决mysql的赋权操作之GRANT ALL PRIVILEGES ON *.*

    这篇文章主要介绍了解决mysql的赋权操作之GRANT ALL PRIVILEGES ON *.* TO ‘root‘@‘%‘ IDENTIFIED BY ‘123456‘ WITH GRANT OPTION问题,本文给大家分享两种情况分析分享解决方案,感兴趣的朋友一起看看吧
    2022-11-11
  • MySQL中create table as 与like的区别分析

    MySQL中create table as 与like的区别分析

    这篇文章主要介绍了MySQL中create table as 与like的区别,结合实例分析了二者在使用中的具体区别与主要用途,需要的朋友可以参考下
    2016-01-01
  • 如何给mysql数据库重新命名(操作步骤)

    如何给mysql数据库重新命名(操作步骤)

    这篇文章主要介绍了如何给mysql数据库重新命名,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-05-05
  • MySQL插入时间戳字段的值实现

    MySQL插入时间戳字段的值实现

    在MySQL中,我们经常会遇到需要插入时间戳字段的情况,包括使用NOW()函数插入当前时间戳,使用FROM_UNIXTIME()插入指定时间戳,本文就来介绍一下,感兴趣的可以了解一下
    2024-09-09
  • Mysql分库分表实现方式

    Mysql分库分表实现方式

    这篇文章详细介绍了分库分表的概念,原因,如何实现,以及不同中间件的优缺点,同时,也介绍了如何进行数据迁移和扩容缩容,以及如何处理分库分表后的ID和事务问题
    2025-02-02
  • win10家庭版64位下mysql 8.0.15 安装配置方法图文教程

    win10家庭版64位下mysql 8.0.15 安装配置方法图文教程

    这篇文章主要为大家详细介绍了win10家庭版64位下mysql 8.0.15 安装配置方法图文教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-03-03
  • MySQL 字符串函数大全

    MySQL 字符串函数大全

    如果字符串函数提供一个二进制字符串作为参数,结果字符串也是一个二进制字符串。被变换到一个字符串的数字被当作是一个二进制字符串。这仅影响比较 .
    2009-07-07

最新评论