玩转Mysql系列 - 第23篇:mysql索引管理详解

2023-09-20 17:51:10

这是Mysql系列第23篇。

环境:mysql5.7.25,cmd命令中进行演示。

代码中被[]包含的表示可选,|符号分开的表示可选其一。

关于索引的,可以先看一下前2篇文章:

  1. 什么是索引?

  2. mysql索引原理详解

本文主要介绍mysql中索引常见的管理操作。

索引分类

分为聚集索引非聚集索引

聚集索引

每个表有且一定会有一个聚集索引,整个表的数据存储在聚集索引中,mysql索引是采用B+树结构保存在文件中,叶子节点存储主键的值以及对应记录的数据,非叶子节点不存储记录的数据,只存储主键的值。当表中未指定主键时,mysql内部会自动给每条记录添加一个隐藏的rowid字段(默认4个字节)作为主键,用rowid构建聚集索引。

聚集索引在mysql中又叫主键索引

非聚集索引(辅助索引)

也是b+树结构,不过有一点和聚集索引不同,非聚集索引叶子节点存储字段(索引字段)的值以及对应记录主键的值,其他节点只存储字段的值(索引字段)。

每个表可以有多个非聚集索引。

mysql中非聚集索引分为
单列索引

即一个索引只包含一个列。

多列索引(又称复合索引)

即一个索引包含多个列。

唯一索引

索引列的值必须唯一,允许有一个空值。

数据检索的过程

看一张图:

图片

上面的表中有2个索引:id作为主键索引,name作为辅助索引。

innodb我们用的最多,我们只看图中左边的innodb中数据检索过程:

如果需要查询id=14的数据,只需要在左边的主键索引中检索就可以了。

如果需要搜索name='Ellison'的数据,需要2步:

  1. 先在辅助索引中检索到name='Ellison'的数据,获取id为14

  2. 再到主键索引中检索id为14的记录

辅助索引相对于主键索引多了第二步。

索引管理

创建索引
方式1:
create [unique] index 索引名称 on 表名(列名[(length)]);
方式2:
alter 表名 add [unique] index 索引名称 on (列名[(length)]);

如果字段是char、varchar类型,length可以小于字段实际长度,如果是blog、text等长文本类型,必须指定length。

[unique]:中括号代表可以省略,如果加上了unique,表示创建唯一索引。

如果table后面只写一个字段,就是单列索引,如果写多个字段,就是复合索引,多个字段之间用逗号隔开。

删除索引
drop index 索引名称 on 表名;
查看索引

查看某个表中所有的索引信息如下:

show index from 表名;
索引修改

可以先删除索引,再重建索引。

示例

准备200万数据
/*建库javacode2018*/
DROP DATABASE IF EXISTS javacode2018;
CREATE DATABASE javacode2018;
USE javacode2018;

/*建表test1*/
DROP TABLE IF EXISTS test1;
CREATE TABLE test1 (
  id     INT NOT NULL COMMENT '编号',
  name   VARCHAR(20) NOT NULL COMMENT '姓名',
  sex TINYINT NOT NULL COMMENT '性别,1:男,2:女',
  email  VARCHAR(50)
);

/*准备数据*/
DROP PROCEDURE IF EXISTS proc1;
DELIMITER $
CREATE PROCEDURE proc1()
  BEGIN
    DECLARE i INT DEFAULT 1;
    START TRANSACTION;
    WHILE i <= 2000000 DO
      INSERT INTO test1 (id, name, sex, email) VALUES (i,concat('javacode',i),if(mod(i,2),1,2),concat('javacode',i,'@163.com'));
      SET i = i + 1;
      if i%10000=0 THEN
        COMMIT;
        START TRANSACTION;
      END IF;
    END WHILE;
    COMMIT;
  END $

DELIMITER ;
CALL proc1();
SELECT count(*) FROM test1;

上图中使用存储过程循环插入了200万记录,表中有4个字段,除了sex列,其他列的值都是没有重复的,表中还未建索引。

插入的200万数据中,id,name,email的值都是没有重复的。

无索引我们体验一下查询速度
mysql> select * from test1 a where a.id = 1;
+----+-----------+-----+-------------------+
| id | name      | sex | email             |
+----+-----------+-----+-------------------+
|  1 | javacode1 |   1 | javacode1@163.com |
+----+-----------+-----+-------------------+
1 row in set (0.77 sec)

上面我们按id查询了一条记录耗时770毫秒,我们在id上面创建个索引感受一下速度。

创建索引

我们在id上面创建一个索引,感受一下:

mysql> create index idx1 on test1 (id);
Query OK, 0 rows affected (2.82 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> select * from test1 a where a.id = 1;
+----+-----------+-----+-------------------+
| id | name      | sex | email             |
+----+-----------+-----+-------------------+
|  1 | javacode1 |   1 | javacode1@163.com |
+----+-----------+-----+-------------------+
1 row in set (0.00 sec)

上面的查询是不是非常快,耗时1毫秒都不到。

我们在name上也创建个索引,感受一下查询的神速,如下:

mysql> create unique index idx2 on test1(name);
Query OK, 0 rows affected (9.67 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> select * from test1 where name = 'javacode1';
+----+-----------+-----+-------------------+
| id | name      | sex | email             |
+----+-----------+-----+-------------------+
|  1 | javacode1 |   1 | javacode1@163.com |
+----+-----------+-----+-------------------+
1 row in set (0.00 sec)

查询快如闪电,有没有,索引是如此的神奇。

创建索引并指定长度

通过email检索一下数据

mysql> select * from test1 a where a.email = 'javacode1000085@163.com';
+---------+-----------------+-----+-------------------------+
| id      | name            | sex | email                   |
+---------+-----------------+-----+-------------------------+
| 1000085 | javacode1000085 |   1 | javacode1000085@163.com |
+---------+-----------------+-----+-------------------------+
1 row in set (1.28 sec)

耗时1秒多,回头去看一下插入数据的sql,我们可以看到所有的email记录,每条记录的前面15个字符是不一样的,结尾是一样的(都是@163.com),通过前面15个字符就可以定位一个email了,那么我们可以对email创建索引的时候指定一个长度为15,这样相对于整个email字段更短一些,查询效果是一样的,这样一个页中可以存储更多的索引记录,命令如下:

mysql> create index idx3 on test1 (email(15));
Query OK, 0 rows affected (7.67 sec)
Records: 0  Duplicates: 0  Warnings: 0

然后看一下查询效果:

mysql> select * from test1 a where a.email = 'javacode1000085@163.com';
+---------+-----------------+-----+-------------------------+
| id      | name            | sex | email                   |
+---------+-----------------+-----+-------------------------+
| 1000085 | javacode1000085 |   1 | javacode1000085@163.com |
+---------+-----------------+-----+-------------------------+
1 row in set (0.00 sec)

耗时不到1毫秒,神速。

查看表中的索引

我们看一下test1表中的所有索引,如下:

mysql> show index from test1;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test1 |          0 | idx2     |            1 | name        | A         |     1992727 |     NULL | NULL   |      | BTREE      |         |               |
| test1 |          1 | idx1     |            1 | id          | A         |     1992727 |     NULL | NULL   |      | BTREE      |         |               |
| test1 |          1 | idx3     |            1 | email       | A         |     1992727 |       15 | NULL   | YES  | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)

可以看到test1表中3个索引的详细信息(索引名称、类型,字段)。

删除索引

我们删除idx1,然后再列出test1表所有索引,如下:

mysql> drop index idx1 on test1;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from test1;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test1 |          0 | idx2     |            1 | name        | A         |     1992727 |     NULL | NULL   |      | BTREE      |         |               |
| test1 |          1 | idx3     |            1 | email       | A         |     1992727 |       15 | NULL   | YES  | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.00 sec)

本篇主要是mysql中索引管理相关一些操作,属于基础知识,希望大家掌握。

下篇文章介绍:

  1. 一个表应该创建哪些索引?

  2. 有索引时sql应该怎么写?

  3. 我的sql为什么不走索引?需要知道内部原理

  4. where条件涉及多个字段多个索引时怎么走?

  5. 多表连接查询、子查询,怎么去利用索引,内部过程是什么样的?

  6. like查询中前面有%的时候为何不走索引?

  7. 字段中使用函数的时候为什么不走索引?

  8. 字符串查询使用数字作为条件的时候为什么不走索引?、

  9. 索引区分度、索引覆盖、最左匹配、索引排序又是什么?原理是什么?

关于上面各种索引选择的问题,我们会深入其原理,让大家知道为什么是这样?而不是只去记一些优化规则,而不知道其原因,知道其原理用的时候更加得心应手一些。

更多推荐

Oracle数据库体系结构(二)_物理结构

目录1概述2物理结构2.1数据文件2.2控制文件2.4归档日志文件2.5参数文件2.6警报文件2.7跟踪文件2.8备份文件3总结1概述存储结构是Oracle数据库的体系结构之一,是Oracle管理的基础。Oracle存储结构可分为物理结构和逻辑结构。一个数据库的物理结构可包括数据文件、联机日志文件和控制文件及其他的一些

【Docker】深入解析企业中 Docker 仓库的用法和作用

深入解析企业中Docker仓库的用法和作用Docker仓库是企业中管理和分发镜像的关键工具。本文将详细介绍Docker仓库的概念、常见用法以及在企业中的作用,并结合Java代码演示如何使用Docker仓库。1.Docker仓库概述Docker仓库是存储和分享Docker镜像的中心化存储库。它允许开发者将自己的镜像上传到

鸿蒙应用开发(基础篇)之列表组件

一、简介在我们常用的手机应用中,经常会见到一些数据列表,如设置页面、通讯录、商品列表等。下图中两个页面都包含列表,“首页”页面中包含两个网格布局,“商城”页面中包含一个商品列表。上图中的列表中都包含一系列相同宽度的列表项,连续、多行呈现同类数据,例如图片和文本。常见的列表有线性列表(List列表)和网格布局(Grid列

Linux READ_ONCE/WRITE_ONCE宏

文章目录前言一、简介1.1READ_ONCE1.2WRITE_ONCE1.3volatile关键字二、Compilerbarrier2.1barrier2.2READ_ONCE/WRITE_ONCE三、总结参考资料前言最近在看arm64架构内存页表源码部分,发现在遍历页表项的时候经常出现READ_ONCE宏和WRITE

跟我一起写Makefile细节总结学习笔记

文章目录跟我一起写Makefile细节总结学习笔记第一,二章此篇仅为方便查阅记忆,详细的请看[seisman/how-to-write-makefile:跟我一起写Makefile重制版(github.com)](https://github.com/seisman/how-to-write-makefile)Make

AIGC赋能教育 | 虚拟现实:下一代的教室在哪里?

在这个科技迅速进步的时代,全球教育领域正迎来一场前所未有的数字化和技术化变革。而AIGC则是代表了人工智能与教育的融合,它正在改变着学习方式、提高教育质量,并重新定义了教育的未来。我们正在亲眼目睹AIGC如何塑造着全球教育的格局,为学生、教育者和整个社会带来了广泛的机遇和挑战。这个崭新的时代不仅带来了无限可能性,也需要

DDoS是什么?

一.DDoS的定义DDos的前身DoS(DenialofService)攻击,其含义是拒绝服务攻击,这种攻击行为使网站服务器充斥大量的要求回复的信息,消耗网络带宽或系统资源,导致网络或系统不胜负荷而停止提供正常的网络服务。而DDoS分布式拒绝服务,则主要利用Internet上现有机器及系统的漏洞,攻占大量联网主机,使其

SpringMVC之JSON数据返回与异常处理机制

目录一.SpringMVC的JSON数据返回1.导入Maven依赖2.配置spring-mvc.xml3.@ResponseBody注解的使用3.1案例演示1.List集合转JSON2.Map集合转JSON3.返回指定格式String4.@ResponseBody用法5.Jackson5.1介绍5.2常用注解二.异常处

SwiftUI 5.0(iOS 17)TipKit 让用户更懂你的 App

概览作为我们秃头开发者来说,写出一款创意炸裂的App还不足以吸引用户眼球,更重要的是如何让用户用最短的时间掌握我们App的使用技巧。从iOS17开始,推出了全新的TipKit框架专注于此事。有了它,我们再也不用自己写App用户帮助以及使用指南的逻辑和界面了。使用TipKit非常简单,接下来就让我们一起走进TipKit

对于项目中爱抱怨成员,项目经理如何回应?

李佳刚被提拔成项目经理。他是技术部的骨干人员,工作能力很强,已经干了快五年了。公司规模中等,属于比较传统的制造型公司。随着公司升级转型,项目越来越多,难度也增加了。原来那种按部就班的订单式生产被更加灵活、个性化的客户需求所取代,不但技术难度提高了,完成一个项目所涉及的部门、协作单位也增多了。李佳由于出色的工作表现,因此

Java手写决策树和决策树应用拓展案例

Java手写决策树和决策树应用拓展案例1.算法思维导图以下是用mermaid代码表示的决策树算法实现原理的思维导图:#mermaid-svg-DWczpr7jTBRHS9bA{font-family:"trebuchetms",verdana,arial,sans-serif;font-size:16px;fill:#

热文推荐