Mysql进阶索引篇03——2个新特性,11+7条设计原则教你创建索引(二)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 1、索引的声明与使用1.1. 索引的分类先介绍下索引的分类,方便后续介绍索引的创建与设计。

接下来进行查询操作

EXPLAIN SELECT * FROM ts1 ORDER BY a,b DESC LIMIT 5;
• 1

在mysql5.7中,执行结果如下。可以发现,它使用了Using filesort,这是一种外部排序方法,会降低查询的效率。并且它扫描的rows是799条。

再在8.0中执行下,可以看到8.0中使用的是索引Using Index,并且它扫描的rows是5条。

当然,你要是在8.0中执行下面语句,性能就不佳了(a,b的升降序与索引中存储的升降序相反

EXPLAIN SELECT * FROM ts1 ORDER BY a DESC,b LIMIT 5;

因此,如果你频繁需要使用查询a降序,b升序的语句,就建议在建索引时也按照同样的顺序哦。


2.2 隐藏索引

Mysql8.x开始支持把索引设置为隐藏状态。在之前我们多次提到,如果需要频繁对数据进行增、删、改操作,可以先将索引删除。当我们因为删除索引出现了错误,就需要把索引重新创建回来。如果数据表本身较大,这就会造成较大的性能损耗。


因此我们可以通过隐藏索引实现对于索引的软删除。同时,如果你想验证删除索引对于性能的影响,也可以选择隐藏索引。


💁 注意 :

主键不可以设置成为隐藏索引(这样相当于主键失效了)。如果没有显示主键,唯一的非空字段会被隐式的设置为主键,因此这种情况也不能将其设置为隐藏索引。


🎃执行如下sql。创建表时创建一个隐藏索引。

CREATE TABLE book3(
  book_id INT ,
  book_name VARCHAR(100),
  authors VARCHAR(100),
  info VARCHAR(100) ,
  comment VARCHAR(100),
  year_publication YEAR,
  INDEX idx_cmt(comment) INVISIBLE
);
mysql> SHOW INDEX FROM book3;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| book3 |          1 | idx_cmt  |            1 | comment     | A         |           0 |     NULL |   NULL | YES  | BTREE      |         |               | NO      | NULL       |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
1 row in set (0.01 sec)

执行下查询操作。可以看到possible_keysNull,说明没有使用索引。

mysql>  EXPLAIN SELECT * FROM book3 WHERE COMMENT="XXX";
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | book3 | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

🎄 可以在已经存在的表上创建一个隐藏索引。

CREATE INDEX indexname
ON tablename(propname[(length)]) INVISIBLE;

🎀 还可以使用Alter在已经存在的表上创建一个隐藏索引。

ALTER TABLE tablename
ADD INDEX indexname (propname [(length)]) INVISIBLE;

🎁可以切换索引可见状态 已存在的索引可通过如下语句切换可见状态:

ALTER TABLE tablename ALTER INDEX index_name INVISIBLE; #切换成隐藏索引
ALTER TABLE tablename ALTER INDEX index_name VISIBLE; #切换成非隐藏索引

👩‍🏫注意:

隐藏索引在表中数据发生变化时也需要对应进行索引维护,如果一个索引需要长期隐藏,最好还是将其删除,从而降低性能上的损耗。

2.3 使隐藏索引对优化器可见(了解)

隐藏索引对优化器默认部可见,查看下优化器的配置。

mysql> select @@optimizer_switch \G
*************************** 1. row ***************************
@@optimizer_switch: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on,use_invisible_indexes=off,skip_scan=on,hash_join=on,subquery_to_derived=off,prefer_ordering_index=on,hypergraph_optimizer=off,derived_condition_pushdown=on
1 row in set (0.01 sec)

在上面的输出可以看到use_invisible_indexes=off.说明隐藏索引默认对于查询优化器不可见。

可以更改

mysql> set session optimizer_switch="use_invisible_indexes=on";
Query OK, 0 rows affected (0.00 sec)

更改以后执行查询操作,possible_keys idx_cmt ,而且我们还将其设置为隐藏索引了。这就说明隐藏索引对于查询优化器可见了

mysql> Alter table book3 alter index idx_cmt invisible;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql>  EXPLAIN SELECT * FROM book3 WHERE COMMENT="XXX";
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | book3 | NULL       | ref  | idx_cmt       | idx_cmt | 303     | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

3.适合创建索引的11种情况


3.1 数据准备

准备下数据。由于需要使用函数与存储过程,这里建议使用图形化的操作界面,比如navicat

CREATE DATABASE atguigudb1;
USE atguigudb1;
#1.创建学生表和课程表
CREATE TABLE `student_info` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `student_id` INT NOT NULL ,
  `name` VARCHAR(20) DEFAULT NULL,
  `course_id` INT NOT NULL ,
  `class_id` INT(11) DEFAULT NULL,
  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
   PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `course` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `course_id` INT NOT NULL ,
  `course_name` VARCHAR(40) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

准备生成随机数的函数

#函数1:创建随机产生字符串函数
DELIMITER //
CREATE FUNCTION rand_string(n INT)
  RETURNS VARCHAR(255) #该函数会返回一个字符串
BEGIN
  DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
  DECLARE return_str VARCHAR(255) DEFAULT '';
  DECLARE i INT DEFAULT 0;
  WHILE i < n DO
     SET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));
     SET i = i + 1;
    END WHILE;
    RETURN return_str;
END //
DELIMITER ;
#函数2:创建随机数函数
DELIMITER //
CREATE FUNCTION rand_num (from_num INT ,to_num INT) RETURNS INT(11)
BEGIN 
DECLARE i INT DEFAULT 0; 
SET i = FLOOR(from_num +RAND()*(to_num - from_num+1))  ;
RETURN i; 
END //
DELIMITER ;

在上面创建函数的过程,可能会出现报错。

This function has none of DETERMINISTIC......
• 1


如果出现报错是因为开启了慢查询日志bin-log,主从复制时,主机会将写操作记录在bin-log日志中,从机从bin-log中读取记录执行同步操作,因为使用函数可能导致主机与从机操作时间不一致,会默认关闭函数的创建。通过如下语句来查看下

mysql> SELECT @@log_bin_trust_function_creators;
+-----------------------------------+
| @@log_bin_trust_function_creators |
+-----------------------------------+
|                                 0 |
+-----------------------------------+
1 row in set (0.62 sec)

默认是不允许函数创建。改下,再重新去创建函数就可以了。

set global log_bin_trust_function_creators=1;   # 不加global只是当前窗口有效。
• 1


mysqld重启,上述参数又会消失。永久方法

#windows下:my.ini[mysqld]加上:
log_bin_trust_function_creators=1 
#linux下:/etc/my.cnf下my.cnf[mysqld]加上:
log_bin_trust_function_creators=1

创建插入模拟数据的存储过程

#存储过程1:创建插入课程表存储过程
DELIMITER //
CREATE PROCEDURE insert_course( max_num INT )
BEGIN 
  DECLARE i INT DEFAULT 0; 
  SET autocommit = 0;   #设置手动提交事务
  REPEAT  #循环
  SET i = i + 1;  #赋值
  INSERT INTO course (course_id, course_name ) VALUES
  (rand_num(10000,10100),rand_string(6)); 
  UNTIL i = max_num 
  END REPEAT; 
  COMMIT;  #提交事务
END //
DELIMITER ;
# 存储过程2:创建插入学生信息表存储过程
DELIMITER //
CREATE PROCEDURE insert_stu( max_num INT )
BEGIN 
  DECLARE i INT DEFAULT 0; 
  SET autocommit = 0;   #设置手动提交事务
  REPEAT  #循环
  SET i = i + 1;  #赋值
  INSERT INTO student_info (course_id, class_id ,student_id ,NAME ) VALUES
(rand_num(10000,10100),rand_num(10000,10200),rand_num(1,200000),rand_string(6)); 
  UNTIL i = max_num 
  END REPEAT; 
  COMMIT;  #提交事务
END //
DELIMITER ;

调用存储过程插入数据,因为数据量比较大,所以需要等会(约两三分钟)。

CALL insert_course(100);
CALL insert_stu(1000000);


插完数据可以验证下

mysql> select count(*) from course;
+----------+
| count(*) |
+----------+
|      100 |
+----------+
1 row in set (0.01 sec)
mysql> select count(*) from student_info;
+----------+
| count(*) |
+----------+
|  1000000 |
+----------+
1 row in set (0.09 sec)

3.2 适合创建索引的11种情况

下面适合创建索引的情况都是从B+树数据结构上来考虑的,该专栏前面的文章,已经介绍过B+树。MySql进阶索引篇01——深度讲解索引的数据结构:B+树

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
9天前
|
存储 关系型数据库 MySQL
MySQL 8.0特性-自增变量的持久化
【11月更文挑战第8天】在 MySQL 8.0 之前,自增变量(`AUTO_INCREMENT`)的行为在服务器重启后可能会发生变化,导致意外结果。MySQL 8.0 引入了自增变量的持久化特性,将其信息存储在数据字典中,确保重启后的一致性。这提高了开发和管理的稳定性,减少了主键冲突和数据不一致的风险。默认情况下,MySQL 8.0 启用了这一特性,但在升级时需注意行为变化。
|
27天前
|
存储 关系型数据库 MySQL
阿里面试:为什么要索引?什么是MySQL索引?底层结构是什么?
尼恩是一位资深架构师,他在自己的读者交流群中分享了关于MySQL索引的重要知识点。索引是帮助MySQL高效获取数据的数据结构,主要作用包括显著提升查询速度、降低磁盘I/O次数、优化排序与分组操作以及提升复杂查询的性能。MySQL支持多种索引类型,如主键索引、唯一索引、普通索引、全文索引和空间数据索引。索引的底层数据结构主要是B+树,它能够有效支持范围查询和顺序遍历,同时保持高效的插入、删除和查找性能。尼恩还强调了索引的优缺点,并提供了多个面试题及其解答,帮助读者在面试中脱颖而出。相关资料可在公众号【技术自由圈】获取。
|
18天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
85 1
|
28天前
|
存储 关系型数据库 MySQL
如何在MySQL中进行索引的创建和管理?
【10月更文挑战第16天】如何在MySQL中进行索引的创建和管理?
58 1
|
19天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第26天】数据库作为现代应用系统的核心组件,其性能优化至关重要。本文主要探讨MySQL的索引策略与查询性能调优。通过合理创建索引(如B-Tree、复合索引)和优化查询语句(如使用EXPLAIN、优化分页查询),可以显著提升数据库的响应速度和稳定性。实践中还需定期审查慢查询日志,持续优化性能。
47 0
|
9天前
|
SQL 关系型数据库 MySQL
12 PHP配置数据库MySQL
路老师分享了PHP操作MySQL数据库的方法,包括安装并连接MySQL服务器、选择数据库、执行SQL语句(如插入、更新、删除和查询),以及将结果集返回到数组。通过具体示例代码,详细介绍了每一步的操作流程,帮助读者快速入门PHP与MySQL的交互。
24 1
|
11天前
|
SQL 关系型数据库 MySQL
go语言数据库中mysql驱动安装
【11月更文挑战第2天】
26 4
|
1月前
|
存储 关系型数据库 MySQL
Mysql(4)—数据库索引
数据库索引是用于提高数据检索效率的数据结构,类似于书籍中的索引。它允许用户快速找到数据,而无需扫描整个表。MySQL中的索引可以显著提升查询速度,使数据库操作更加高效。索引的发展经历了从无索引、简单索引到B-树、哈希索引、位图索引、全文索引等多个阶段。
61 3
Mysql(4)—数据库索引
|
20天前
|
关系型数据库 MySQL Linux
在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。
本文介绍了在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。同时,文章还对比了编译源码安装与使用 RPM 包安装的优缺点,帮助读者根据需求选择最合适的方法。通过具体案例,展示了编译源码安装的灵活性和定制性。
61 2
|
23天前
|
存储 关系型数据库 MySQL
MySQL vs. PostgreSQL:选择适合你的开源数据库
在众多开源数据库中,MySQL和PostgreSQL无疑是最受欢迎的两个。它们都有着强大的功能、广泛的社区支持和丰富的生态系统。然而,它们在设计理念、性能特点、功能特性等方面存在着显著的差异。本文将从这三个方面对MySQL和PostgreSQL进行比较,以帮助您选择更适合您需求的开源数据库。
89 4