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

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

3.2.1字段具有唯一性限制

适合创建唯一性索引,适合创建唯一性索引,当然,如果该字段被Unique修饰,具有唯一性约束,会自动创建一个唯一性索引(如果给字段添加了唯一性索引,同样也会自动添加唯一性约束)。这是因为唯一性的字段没有重复值,很适合作为查询条件(可以结合B+树来理解,在叶子节点查找到唯一数据后,无须再进行遍历了),给他们加索引可以在使用其作为查询条件时提升效率。


🙋‍♀️ 业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。(来源:Alibaba)

说明:不要以为唯一索引影响了 insert 速度,这个速度损耗可以忽略,但提高查找速度是明显的。


3.2.2频繁作为 WHERE 查询条件的字段

某个字段在SELECT语句的 WHERE 条件中经常被使用到,那么就需要给这个字段创建索引了。

尤其是在数据量大的情况下,创建普通索引就可以大幅提升数据查询的效率。

查看student_info表中的索引

mysql> SHOW INDEX FROM student_info;
+--------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table        | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+--------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| student_info |          0 | PRIMARY  |            1 | id          | A         |      960509 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
+--------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
1 row in set (0.06 sec)

可以看出student_id没有建立索引。用它作为查询条件查询下。耗时1.07s

mysql> SELECT course_id,class_id,NAME,create_time,student_id
    -> FROM
    -> student_info
    -> WHERE student_id = 123110;
+-----------+----------+--------+---------------------+------------+
| course_id | class_id | NAME   | create_time         | student_id |
+-----------+----------+--------+---------------------+------------+
|     10058 |    10014 | SyNuJn | 2022-05-25 09:30:46 |     123110 |
|     10053 |    10007 | YYVLTl | 2022-05-25 09:31:15 |     123110 |
|     10053 |    10008 | XVIHkg | 2022-05-25 09:32:22 |     123110 |
+-----------+----------+--------+---------------------+------------+
3 rows in set (1.07 sec)

添加索引。耗时5.39s

mysql> AlTER TABLE student_info
    -> ADD INDEX idx_sid(student_id);
Query OK, 0 rows affected (5.39 sec)
Records: 0  Duplicates: 0  Warnings: 0

再查询。耗时0.00s。性能提升杠杠的

mysql> SELECT course_id,class_id,NAME,create_time,student_id
    -> FROM
    -> student_info
    -> WHERE student_id = 123110;
+-----------+----------+--------+---------------------+------------+
| course_id | class_id | NAME   | create_time         | student_id |
+-----------+----------+--------+---------------------+------------+
|     10058 |    10014 | SyNuJn | 2022-05-25 09:30:46 |     123110 |
|     10053 |    10007 | YYVLTl | 2022-05-25 09:31:15 |     123110 |
|     10053 |    10008 | XVIHkg | 2022-05-25 09:32:22 |     123110 |
+-----------+----------+--------+---------------------+------------+
3 rows in set (0.00 sec)

3.2.3 经常 GROUP BY 和 ORDER BY 的列

索引其实就是让数据按照某种顺序进行存储或者检索,而GROUP BY分组查询或者ORDER BY进行排序,如果添加了索引,本身索引的数据就已经排好序了,进行分组查询和排序操作性能不是很nice吗?另外,如果待排序的列有多个,可以在这些列上建立联合索引。


⚽下面在有student_id索引的情况下,查询.

```mysql> SELECT student_id,COUNT(*) AS num
    -> FROM student_info
    -> GROUP BY student_id LIMIT 100;
+------------+-----+
| student_id | num |
+------------+-----+
|          1 |   9 |
//笔者省略了......
|        100 |   4 |
+------------+-----+
100 rows in set (0.00 sec)

删除索引,再来。慢的像蜗牛

mysql> SELECT student_id,COUNT(*) AS num
    -> FROM student_info
    -> GROUP BY student_id LIMIT 100;
+------------+-----+
| student_id | num |
+------------+-----+
|          1 |   9 |
// ...
|        100 |   4 |
+------------+-----+
100 rows in set (10.31 sec)

🏀 如果同时使用GROUP BYORDER BY,先看看不加索引的情况

mysql> SELECT student_id,COUNT(*) AS num FROM student_info
    -> GROUP BY student_id
    -> ORDER BY create_time DESC
    -> LIMIT 100;
ERROR 1055 (42000): Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'atguigudb1.student_info.create_time' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

出现了一个异常信息,这是因为我们使用的sql_modeonly_full_group_by.修改下再来,时间代价是6.61秒

mysql> SELECT @@sql_mode;
+-----------------------------------------------------------------------------------------------------------------------+
| @@sql_mode                                                                                                            |
+-----------------------------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+-----------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> SET @@sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @@sql_mode;
+----------------------------------------------------------------------------------------------------+
| @@sql_mode                                                                                         |
+----------------------------------------------------------------------------------------------------+
| STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+----------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT student_id,COUNT(*) AS num FROM student_info
    -> GROUP BY student_id
    -> ORDER BY create_time DESC
    -> LIMIT 100;
+------------+-----+
| student_id | num |
+------------+-----+
|      90433 |   1 |
...
|     144379 |   1 |
+------------+-----+
100 rows in set (6.61 sec)

再看看两个字段分别建立单列索引的情况,5.26s,快了一点点

mysql> ALTER TABLE student_info ADD INDEX idx_sid(student_id);
Query OK, 0 rows affected (3.61 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> ALTER TABLE student_info ADD INDEX idx_cre_time(create_time);
Query OK, 0 rows affected (3.52 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> SELECT student_id,COUNT(*) AS num FROM student_info
    -> GROUP BY student_id
    -> ORDER BY create_time DESC
    -> LIMIT 100;
+------------+-----+
| student_id | num |
+------------+-----+
|      90433 |   1 |
|      88221 |   1 |
//......
|     144379 |   1 |
+------------+-----+
100 rows in set (5.26 sec)

分析下它的查询过程,原来我们只用了一个索引,由于我们是先GROUP BY student_id,后ORDER BY create_time,我们实际上只使用了索引idx_sid

mysql> EXPLAIN SELECT student_id,COUNT(*) AS num FROM student_info
    -> GROUP BY student_id
    -> ORDER BY create_time DESC
    -> LIMIT 100;
+----+-------------+--------------+------------+-------+---------------+---------+---------+------+--------+----------+---------------------------------+
| id | select_type | table        | partitions | type  | possible_keys | key     | key_len | ref  | rows   | filtered | Extra                           |
+----+-------------+--------------+------------+-------+---------------+---------+---------+------+--------+----------+---------------------------------+
|  1 | SIMPLE      | student_info | NULL       | index | idx_sid       | idx_sid | 4       | NULL | 997449 |   100.00 | Using temporary; Using filesort |
+----+-------------+--------------+------------+-------+---------------+---------+---------+------+--------+----------+---------------------------------+
1 row in set, 1 warning (0.01 sec)

建立联合索引的情况,芜湖起飞

mysql>  ALTER TABLE student_info ADD INDEX idx_sid_cre_time(student_id,create_time DESC);
Query OK, 0 rows affected (4.71 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> EXPLAIN SELECT student_id,COUNT(*) AS num FROM student_info
    -> GROUP BY student_id
    -> ORDER BY create_time DESC
    -> LIMIT 100;
+----+-------------+--------------+------------+-------+--------------------------+------------------+---------+------+--------+----------+----------------------------------------------+
| id | select_type | table        | partitions | type  | possible_keys            | key              | key_len | ref  | rows   | filtered | Extra                                        |
+----+-------------+--------------+------------+-------+--------------------------+------------------+---------+------+--------+----------+----------------------------------------------+
|  1 | SIMPLE      | student_info | NULL       | index | idx_sid,idx_sid_cre_time | idx_sid_cre_time | 10      | NULL | 997449 |   100.00 | Using index; Using temporary; Using filesort |
+----+-------------+--------------+------------+-------+--------------------------+------------------+---------+------+--------+----------+----------------------------------------------+
1 row in set, 1 warning (0.00 sec)

再来,交换字段顺序建立联合索引idx_cre_time_sid,下面查询真正使用的索引keyidx_sid ,当然,由于这里存在缓存,所以查询速度很快,实际上它应该比使用idx_sid_cre_time慢。读者自己测试可以关闭缓存,作者这里偷个懒

mysql> ALTER TABLE student_info ADD INDEX idx_cre_time_sid(create_time DESC,student_id);
Query OK, 0 rows affected (4.50 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> DROP INDEX idx_sid_cre_time ON student_info;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> EXPLAIN SELECT student_id,COUNT(*) AS num FROM student_info
    -> GROUP BY student_id
    -> ORDER BY create_time DESC
    -> LIMIT 100;
+----+-------------+--------------+------------+-------+--------------------------+---------+---------+------+--------+----------+---------------------------------+
| id | select_type | table        | partitions | type  | possible_keys            | key     | key_len | ref  | rows   | filtered | Extra                           |
+----+-------------+--------------+------------+-------+--------------------------+---------+---------+------+--------+----------+---------------------------------+
|  1 | SIMPLE      | student_info | NULL       | index | idx_sid,idx_cre_time_sid | idx_sid | 4       | NULL | 997449 |   100.00 | Using temporary; Using filesort |
+----+-------------+--------------+------------+-------+--------------------------+---------+---------+------+--------+----------+---------------------------------+
1 row in set, 1 warning (0.00 sec)
相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
1月前
|
SQL 监控 关系型数据库
MySQL事务处理:ACID特性与实战应用
本文深入解析了MySQL事务处理机制及ACID特性,通过银行转账、批量操作等实际案例展示了事务的应用技巧,并提供了性能优化方案。内容涵盖事务操作、一致性保障、并发控制、持久性机制、分布式事务及最佳实践,助力开发者构建高可靠数据库系统。
|
3月前
|
存储 SQL 关系型数据库
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
|
3月前
|
存储 关系型数据库 MySQL
MySQL数据库索引的数据结构?
MySQL中默认使用B+tree索引,它是一种多路平衡搜索树,具有树高较低、检索速度快的特点。所有数据存储在叶子节点,非叶子节点仅作索引,且叶子节点形成双向链表,便于区间查询。
102 4
|
23天前
|
存储 关系型数据库 MySQL
介绍MySQL的InnoDB引擎特性
总结而言 , Inno DB 引搞 是 MySQL 中 高 性 能 , 高 可靠 的 存 储选项 , 宽泛 应用于要求强 复杂交易处理场景 。
61 15
|
16天前
|
关系型数据库 MySQL 数据库
MySql事务以及事务的四大特性
事务是数据库操作的基本单元,具有ACID四大特性:原子性、一致性、隔离性、持久性。它确保数据的正确性与完整性。并发事务可能引发脏读、不可重复读、幻读等问题,数据库通过不同隔离级别(如读未提交、读已提交、可重复读、串行化)加以解决。MySQL默认使用可重复读级别。高隔离级别虽能更好处理并发问题,但会降低性能。
|
3月前
|
存储 SQL 关系型数据库
MySQL 核心知识与索引优化全解析
本文系统梳理了 MySQL 的核心知识与索引优化策略。在基础概念部分,阐述了 char 与 varchar 在存储方式和性能上的差异,以及事务的 ACID 特性、并发事务问题及对应的隔离级别(MySQL 默认 REPEATABLE READ)。 索引基础部分,详解了 InnoDB 默认的 B+tree 索引结构(多路平衡树、叶子节点存数据、双向链表支持区间查询),区分了聚簇索引(数据与索引共存,唯一)和二级索引(数据与索引分离,多个),解释了回表查询的概念及优化方法,并分析了 B+tree 作为索引结构的优势(树高低、效率稳、支持区间查询)。 索引优化部分,列出了索引创建的六大原则
|
4月前
|
存储 关系型数据库 MySQL
MySQL覆盖索引解释
总之,覆盖索引就像是图书馆中那些使得搜索变得极为迅速和简单的工具,一旦正确使用,就会让你的数据库查询飞快而轻便。让数据检索就像是读者在图书目录中以最快速度找到所需信息一样简便。这样的效率和速度,让覆盖索引成为数据库优化师傅们手中的尚方宝剑,既能够提升性能,又能够保持系统的整洁高效。
125 9
|
1月前
|
安全 关系型数据库 MySQL
MySQL安全最佳实践:保护你的数据库
本文深入探讨了MySQL数据库的安全防护体系,涵盖认证安全、访问控制、网络安全、数据加密、审计监控、备份恢复、操作系统安全、应急响应等多个方面。通过具体配置示例,为企业提供了一套全面的安全实践方案,帮助强化数据库安全,防止数据泄露和未授权访问,保障企业数据资产安全。
|
16天前
|
缓存 关系型数据库 BI
使用MYSQL Report分析数据库性能(下)
使用MYSQL Report分析数据库性能
54 3
|
23天前
|
关系型数据库 MySQL 数据库
自建数据库如何迁移至RDS MySQL实例
数据库迁移是一项复杂且耗时的工程,需考虑数据安全、完整性及业务中断影响。使用阿里云数据传输服务DTS,可快速、平滑完成迁移任务,将应用停机时间降至分钟级。您还可通过全量备份自建数据库并恢复至RDS MySQL实例,实现间接迁移上云。

热门文章

最新文章

推荐镜像

更多