MySQL 之INDEX 索引(Index Index of MySQL)
MySQL 之INDEX 索引
1.4 INDEX 索引
1.4.1 索引介绍
索引:是排序的快速查找的特殊数据结构,定义作为查找条件的字段上,又称为键 key,索引通过存储引擎实现。
优点
-
大大加快数据的检索速度;
-
创建唯一性索引,保证数据库表中每一行数据的唯一性;
-
加速表和表之间的连接;
-
在使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间。
缺点
-
索引需要占物理空间。
-
当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度。
索引类型
-
B+ TREE、HASH、R TREE、FULL TEXT
-
聚簇(集)索引、非聚簇索引:数据和索引是否存储在一起
-
主键索引、二级(辅助)索引
-
稠密索引、稀疏索引:是否索引了每一个数据项
-
简单索引、组合索引: 是否是多个字段的索引
-
左前缀索引:取前面的字符做索引
-
覆盖索引:从索引中即可取出要查询的数据,性能高
1.4.2 索引结构
参考链接:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
树的简介
树跟数组、链表、堆栈一样,是一种数据结构。它由有限个节点,组成具有层次关系的集合。因为它看起来像一棵树,所以得其名。
树是包含n(n为整数,大于0)个结点, n-1条边的有穷集,它有以下特点
-
每个结点或者无子结点或者只有有限个子结点
-
有一个特殊的结点,它没有父结点,称为根结点
-
每一个非根节点有且只有一个父节点
-
树里面没有环路
概念相关
-
结点的度:一个结点含有的子结点个数称为该结点的度
-
树的度:一棵树中,最大结点的度称为树的度
-
父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点
-
深度:对于任意结点N,N的深度为从根到n的唯一路径长,根结点的深度为0
-
高度:对于任意结点N,N的高度为从n到一片树叶的最长路径长,所有树叶的高度为0
树的分类
按照有序性,可以分为有序树和无序树:
-
无序树:树中任意节点的子结点之间没有顺序关系
-
有序树:树中任意节点的子结点之间有顺序关系
按照节点包含子树个数,可以分为B树和二叉树,二叉树可以分为以下几种:
-
二叉树:每个节点最多含有两个子树的树称为二叉树
-
二叉查找树:首先它是一颗二叉树,若左子树不空,则左子树上所有结点的值均小于它的根结点的值;若右子树不空,则右子树上所有结点的值均大于它的根结点的值,左、右子树也分别为二叉排序树
-
满二叉树:叶节点除外的所有节点均含有两个子树的树被称为满二叉树
-
完全二叉树:如果一颗二叉树除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布
-
霍夫曼树:带权路径最短的二叉树
-
红黑树:红黑树是一种特殊的二叉查找树,每个节点都是黑色或者红色,根节点、叶子节点是黑色。如果一个节点是红色的,则它的子节点必须是黑色的
-
平衡二叉树(AVL):一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树
二叉树
二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树。
参考链接:https://www.cs.usfca.edu/~galles/visualization/BST.html
红黑树
红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。
红黑树特点
-
根节点是黑色的,叶节点是不存储数据的黑色空节点
-
任何相邻的两个节点不能同时为红色,红色节点被黑色节点隔开,红色节点的子节点是黑色的
-
任意节点到其可到达的叶节点间包含相同数量的黑色节点,保证任何路径相差不会超出2倍,从而实现基本平衡
参考链接:https://www.cs.usfca.edu/~galles/visualization/RedBlack.html
B-树
B-树,读作B树,中间的横线是连字符,不是减号,B树将一个节点的大小设置为每个数据页(Page,也可以称为块,block)的大小,一般是16KB,并且,B树中是将数据和索引放在一起的,以减少IO次数,加快查询速度,一个节点能放多少数据,通常取决于一条数据占用的空间大小。
mysql> show variables like '%page_size%';+------------------+-------+| Variable_name | Value |+------------------+-------+| innodb_page_size | 16384 || large_page_size | 0 |+------------------+-------+2 rows in set (0.00 sec)
B+树索引
B+树是B-树的变体,也是一棵多路搜索树,MySQL普遍使用B+树来实现索引。
https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html
B+树和B-树的主要区别:
-
B-树内部节点是保存数据的,而B+树内部节点是不保存数据的,只作索引作用,它的叶子节点才保存数据。
-
B+树相邻的叶子节点之间是通过链表指针连起来的,B-树却不是。
-
查找过程中,B-树在找到具体的数值以后就结束,而B+树则需要通过索引找到叶子结点中的数据才结束
-
B-树中任何一个关键字出现且只出现在一个结点中,而B+树可以出现多次。
可以使用B+Tree索引的查询类型(假设前提:姓,名,年龄三个字段建立了一个复合索引)
-
全值匹配:精确所有索引列,如:姓zhang,名ming,年龄20
-
匹配最左前缀:即只使用索引的第一列,如:姓zhang
-
匹配列前缀:只匹配一列值开头部分,如:姓以w开头的记录
-
匹配范围值:如:姓wang和姓zhang之间
-
精确匹配某一列并范围匹配另一列:如:姓wang,名以x开头的记录
-
只访问索引的查询
B+Tree索引的限制
-
如不从最左列开始,则无法使用索引,如:查找名为xiaoming,或姓为g结尾
-
不能跳过索引中的列:如:查找姓为wang,年龄30的,只能使用索引第一列
特别提示
-
索引列的顺序和查询语句的写法应相匹配,才能更好的利用索引
-
为优化性能,可能需要针对相同的列但顺序不同创建不同的索引来满足不同类型的查询需求
Hash索引
-
Hash索引:基于哈希表实现,只有精确匹配索引中的所有列的查询才有效,索引自身只存储索引列对应的哈希值和数据指针,索引结构紧凑,查询性能好。
-
Memory 存储引擎支持显式 hash 索引,InnoDB 和 MyISAM 存储引擎不支持。
-
适用场景:只支持等值比较查询,包括=,<=>,IN()。
不适合使用hash索引的场景
-
不适用于顺序查询:索引存储顺序的不是值的顺序
-
不支持模糊匹配
-
不支持范围查询
-
不支持部分索引列匹配查找:如A,B列索引,只查询A列索引无效
地理空间数据索引 R-Tree( Geospatial indexing )
MyISAM 支持地理空间索引,可使用任意维度组合查询,使用特有的函数访问,常用于做地理数据存储,使用不多。
InnoDB从MySQL5.7之后也开始支持
全文索引(FULLTEXT)
在文本中查找关键词,而不是直接比较索引中的值,类似搜索引擎
InnoDB 从 MySQL 5.6 之后也开始支持
聚簇和非聚簇索引,主键和二级索引
在 MySQL 的 InnoDB 引擎中,每个索引都会对应一棵 B+ 树,而聚簇索引和非聚簇索引最大的区别在于叶子节点存储的数据不同,聚簇索引叶子节点存储的是行数据,因此通过聚簇索引可以直接找到真正的行数据;而非聚簇索引叶子节点存储的是主键信息,所以使用非聚簇索引还需要回表查询,因此我们可以得出聚簇索引和非聚簇索引的区别主要有以下几个:
-
聚簇索引叶子节点存储的是行数据;而非聚簇索引叶子节点存储的是聚簇索引(通常是主键 ID)。
-
聚簇索引查询效率更高,而非聚簇索引需要进行回表查询,因此性能不如聚簇索引。
-
聚簇索引一般为主键索引,而主键一个表中只能有一个,因此聚簇索引一个表中也只能有一个,而非聚簇索引则没有数量上的限制。
冗余和重复索引
-
冗余索引:(A),(A,B),注意如果同时存在,仍可能会使用(A)索引
-
重复索引:已经有索引,再次建立索引
1.4.3 索引优化
参考资料:阿里的《Java开发手册》
https://developer.aliyun.com/topic/java2020
-
独立地使用列:尽量避免其参与运算,独立的列指索引列不能是表达式的一部分,也不能是函数的
-
参数,在where条件中,始终将索引列单独放在比较符号的一侧,尽量不要在列上进行运算(函数操作和表达式操作)
-
左前缀索引:构建指定索引字段的左侧的字符数,要通过索引选择性(不重复的索引值和数据表的记录总数的比值)来评估,尽量使用短索引,如果可以,应该制定一个前缀长度
-
多列索引:AND操作时更适合使用多列索引,而非为每个列创建单独的索引
-
选择合适的索引列顺序:无排序和分组时,将选择性最高放左侧
-
只要列中含有NULL值,就最好不要在此列设置索引,复合索引如果有NULL值,此列在使用时也不会使用索引
-
对于经常在where子句使用的列,最好设置索引
-
对于有多个列where或者order by子句,应该建立复合索引
-
对于like语句,以 % 或者 _ 开头的不会使用索引,以 % 结尾会使用索引
-
尽量不要使用not in和<>操作,虽然可能使用索引,但性能不高
-
不要使用RLIKE正则表达式会导致索引失效
-
查询时,能不要就不用,尽量写全字段名,比如:select id,name,age from students;
-
大部分情况连接效率远大于子查询
-
在有大量记录的表分页时使用limit
-
对于经常使用的查询,可以开启查询缓存
-
多使用explain和profile分析查询语句
-
查看慢查询日志,找出执行时间长的sql语句优化
1.4.4 管理索引
查看帮助
mysql> help index
查看索引
SHOW INDEX FROM [db_name.]tbl_name;
mysql> desc student;+--------+------------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+--------+------------------+------+-----+---------+----------------+| id | int unsigned | NO | PRI | NULL | auto_increment || name | varchar(20) | NO | | NULL | || age | tinyint unsigned | YES | | NULL | || gender | enum('M','F') | YES | | M | |+--------+------------------+------+-----+---------+----------------+4 rows in set (0.00 sec)#默认会在主键上创建索引mysql> show index from student\G*************************** 1. row ***************************Table: studentNon_unique: 0Key_name: PRIMARYSeq_in_index: 1Column_name: idCollation: ACardinality: 6Sub_part: NULLPacked: NULLNull:Index_type: BTREE #B树索引Comment:Index_comment:Visible: YESExpression: NULL1 row in set (0.01 sec)
查看语句是否利用索引
mysql> explain select * from student where id=12\G;*************************** 1. row ***************************id: 1select_type: SIMPLEtable: studentpartitions: NULLtype: const #只读取一次possible_keys: PRIMARYkey: PRIMARY #使用了主键索引key_len: 4ref: constrows: 1 #扫描了1条数据filtered: 100.00Extra: NULL1 row in set, 1 warning (0.00 sec)mysql> explain select * from student where name="wangwu"\G;*************************** 1. row ***************************id: 1select_type: SIMPLEtable: studentpartitions: NULLtype: ALL #全表扫描possible_keys: NULL #没有使用索引字段key: NULL #没有使用索引字段key_len: NULLref: NULLrows: 6 #扫描了6条数据,整个表就是6条数据filtered: 16.67Extra: Using where #在存储引擎检索行后再进行过滤1 row in set, 1 warning (0.00 sec)
创建索引
CREATE [UNIQUE] INDEX index_name ON tbl_name (index_col_name[(length)],...);ALTER TABLE tbl_name ADD INDEX index_name(index_col_name[(length)]);
mysql> create index idx_name on student(name);Query OK, 0 rows affected (0.02 sec)Records: 0 Duplicates: 0 Warnings: 0#create index idx_name on student(name(10)); 表示取 name 字段中的前 10 个字符做索引
再次查看
mysql> show index from student\G*************************** 1. row ***************************Table: studentNon_unique: 0Key_name: PRIMARYSeq_in_index: 1Column_name: idCollation: ACardinality: 6Sub_part: NULLPacked: NULLNull:Index_type: BTREEComment:Index_comment:Visible: YESExpression: NULL*************************** 2. row ***************************Table: studentNon_unique: 1Key_name: idx_nameSeq_in_index: 1Column_name: nameCollation: ACardinality: 6Sub_part: NULLPacked: NULLNull:Index_type: BTREEComment:Index_comment:Visible: YESExpression: NULL2 rows in set (0.00 sec)
再次测试
mysql> explain select * from student where name="wangwu"\G;*************************** 1. row ***************************id: 1select_type: SIMPLEtable: studentpartitions: NULLtype: refpossible_keys: idx_name #使用了索引key: idx_name #使用了索引key_len: 62ref: constrows: 1 #只扫描1条数据filtered: 100.00Extra: NULL1 row in set, 1 warning (0.00 sec)
不是所有查询都能用到索引,B+树索引是左前缀特性,即左匹配可以使用索引
#like 查询左匹配可以使用索引mysql> explain select * from student where name like 'g%'\G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: studentpartitions: NULLtype: rangepossible_keys: idx_name #索引key: idx_name #索引key_len: 62ref: NULLrows: 1filtered: 100.00Extra: Using index condition1 row in set, 1 warning (0.00 sec)#like 查询右匹配不使用索引mysql> explain select * from student where name like '%g'\G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: studentpartitions: NULLtype: ALL #全表扫描possible_keys: NULL #不走索引key: NULL #不走索引key_len: NULLref: NULLrows: 6filtered: 16.67Extra: Using where1 row in set, 1 warning (0.00 sec)#like 查询包含匹配不使用索引mysql> explain select * from student where name like '%g%'\G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: studentpartitions: NULLtype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: 6filtered: 16.67Extra: Using where1 row in set, 1 warning (0.00 sec)
mariadb 中关于索引利用的优化
MariaDB [testdb]> select count(*) from student;+----------+| count(*) |+----------+| 28 |+----------+1 row in set (0.000 sec)MariaDB [testdb]> select count(*) from student where name like 'm%';+----------+| count(*) |+----------+| 22 |+----------+1 row in set (0.000 sec)MariaDB [testdb]> select count(*) from student where name like 'z%';+----------+| count(*) |+----------+| 3 |+----------+1 row in set (0.000 sec)
MariaDB [testdb]> show index from student\G*************************** 1. row ***************************Table: studentNon_unique: 0Key_name: PRIMARYSeq_in_index: 1Column_name: idCollation: ACardinality: 28Sub_part: NULLPacked: NULLNull:Index_type: BTREEComment:Index_comment:*************************** 2. row ***************************Table: studentNon_unique: 1Key_name: idx_nameSeq_in_index: 1Column_name: nameCollation: ACardinality: 28Sub_part: NULLPacked: NULLNull:Index_type: BTREEComment:Index_comment:2 rows in set (0.001 sec)
MariaDB [testdb]> explain select * from student where name like 'm%'\G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: studenttype: ALL #全表扫描possible_keys: idx_name #可能会用到的索引key: NULL #没有使用索引key_len: NULLref: NULLrows: 28Extra: Using where1 row in set (0.000 sec)MariaDB [testdb]> explain select * from student where name like 'z%'\G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: studenttype: range #范围查询possible_keys: idx_name #可能会用到的索引key: idx_name #实际使用了索引key_len: 62ref: NULLrows: 3Extra: Using index condition1 row in set (0.000 sec)
全表总共28条记录,name 字段中,以 m 开头的有22条,以 z 开头的有3条,所以在此情况下,查询以 m 开头内容,直接全表扫描反而会更快这是 mariadb 中的优化,MySQL8.0 中也有此功能,但旧版本中没有此优化
删除索引
DROP INDEX index_name ON tbl_name;ALTER TABLE tbl_name DROP INDEX index_name(index_col_name);
#删除索引mysql> drop index idx_name on student;Query OK, 0 rows affected (0.02 sec)Records: 0 Duplicates: 0 Warnings: 0
再次测试
mysql> explain select * from student where name="wangwu"\G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: studentpartitions: NULLtype: ALL #全表扫描possible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: 6filtered: 16.67Extra: Using where1 row in set, 1 warning (0.01 sec)
查看索引的使用
SET GLOBAL userstat=1;SHOW INDEX_STATISTICS;
#仅在mariadb中使用MariaDB [testdb]> select @@userstat;+------------+| @@userstat |+------------+| 0 |+------------+1 row in set (0.000 sec)#开启MariaDB [testdb]> SET GLOBAL userstat=1;Query OK, 0 rows affected (0.000 sec)#查看MariaDB [testdb]> SHOW INDEX_STATISTICS;Empty set (0.001 sec)#查询MariaDB [testdb]> select * from student where id=13;+----+----------+------+--------+| id | name | age | gender |+----+----------+------+--------+| 13 | zhangfei | 20 | F |+----+----------+------+--------+1 row in set (0.000 sec)MariaDB [testdb]> select * from student where name like 'z%';+----+-------------+------+--------+| id | name | age | gender |+----+-------------+------+--------+| 13 | zhangfei | 20 | F || 11 | zhangsan | 12 | M || 16 | zhugeiliang | 39 | M |+----+-------------+------+--------+3 rows in set (0.001 sec)#再次查看MariaDB [testdb]> SHOW INDEX_STATISTICS;+--------------+------------+------------+-----------+| Table_schema | Table_name | Index_name | Rows_read |+--------------+------------+------------+-----------+| testdb | student | idx_name | 3 || testdb | student | PRIMARY | 1 |+--------------+------------+------------+-----------+2 rows in set (0.000 sec)
优化表空间
OPTIMIZE TABLE tb_name;
对 MySQL 进行大量或频繁的写操作(insert,delete,update),容易产生碎片,这些碎片会影响MySQL 性能。在此情况下,我们可以通过 optimize 命令来进行优化。此命令在使用时会锁表,需要保证在不对业务产生影响的情况下使用。
这里的碎片指的是,经过某些操作,导致数据库中的表对应的硬盘上的物理文件中的数据不是紧密排列的。
1.4.5 EXPLAIN 工具
可以通过EXPLAIN来分析索引的有效性,获取查询执行计划信息,用来查看查询优化器如何执行查询。
官方文档
https://dev.mysql.com/doc/refman/5.7/en/explain-output.htmlhttps://dev.mysql.com/doc/refman/8.0/en/explain-output.html
格式
EXPLAIN SELECT clause
mysql> explain select * from student where id=13\G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: studentpartitions: NULLtype: constpossible_keys: PRIMARY #可能用到的键key: PRIMARYkey_len: 4ref: constrows: 1filtered: 100.00Extra: NULL1 row in set, 1 warning (0.00 sec)
EXPLAIN输出信息说明
-
id:执行编号,标识select所属的行。如果在语句中没子查询或关联查询,只有唯一的 select,每行都将显示1。否则,内层的 select 语句一般会顺序编号,对应于其在原始语句中的位置,如果explain的结果包括多个id值,则数字越大越先执行;而对于相同id的行,则表示从上往下依次执行。
-
select_type:查询类型,具体见下表。
-
table:具体查询的表名,如查 SQL 语句中定义了别名,则此处显示别名 。
-
partitions:当前查询匹配记录的分区。对于未分区的表,返回 NULL。
-
type:关联类型或访问类型,即 MySQL 决定的如何去查询表中的行的方式,具体见下表。
-
possible_keys:查询可能会用到的索引,此处列出的索引字段是在真正执行查询前的优化过程中创建的,因此有些不会被使用。
-
key:实际查询中用到的索引 。
-
key_len:实际查询中,使用索引数据中的字节数,可通过该列计算查询中使用的索引的长度,key_len 显示的值为索引字段的最大可能长度,并非实际使用长度,即 key_len 是根据表定义计算而得,不是通过表内检索出的,不损失精确性的情况下,长度越短越好 。
-
ref:当使用索引列等值查询时,与索引列进行等值匹配的对象信息,列与索引的比较,表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值,如果 ref 是一个函数,则使用的值是函数的结果。要想查看是哪个函数,可在EXPLAIN语句之后紧跟一个SHOW WARNING语句。
-
rows:为了找到所需的行而需要读取的行数,估算值,不精确。
-
filtered:按表条件过滤的行百分比,表示符合查询条件的数据百分比,最大100。用 rows × filtered 可获得和下一张表连接的行数。
-
Extra:展示有关本次查询的附加信息,具体见下表。
select_type 查询类型具体说明
| 关键字 | 说明 |
| SIMPLE | 简单查询(没有使用 UNION 或子查询) |
| PRIMARY | 最外层的查询 |
| UNION | 联合查询,在 UNION 中的第二个和随后的 SELECT 被标记为 UNION,如果UNION 被 FROM 子句中的子查询包含,那么它的第一个 SELECT 会被标记为DERIVED |
| DEPENDENTUNION | UNION 中的第二个或后面的查询,依赖了外层查询 |
| UNION RESULT | UNION 查询结果 |
| SUBQUERY | 子查询中的第一个 SELECT 查询 |
| DEPENDENT SUBQUERY | 子查询中的第一个 SELECT 查询,依赖了外层查询 |
| DERIVED | 用来表示包含在 FROM 子句的子查询中的 SELECT , MySQL 会递归执行并将结果放到一个临时表中,MySQL 内部将此临时表称为 DERIVED table(派生表),因为该临时表是从子查询中派生出来的 |
| DEPENDENT DERIVED | 派生表,并且有依赖于其它表 |
| MALTERIALIZED | 物化子查询 |
| UNCACHEABLE SUBQUERY | 子查询,但结果无法缓存,必须对于外部查询的每一行重新评估 |
| UNCACHEABLEUNION | UNION 属于 UNCACHEABLE SUBQUERY 的第二个或后面的查询 |
type 关联类型具体说明,性能从好到坏排序
| 关键字 | 说明 |
| NULL | MySQL 在优化过程中分解语句,执行时甚至不用访问表或索引,此种查询最高效 |
| system | 该表只有一行(相当于系统表),system 是 const 类型的特例 |
| const | 针对主键或唯一索引的等值查询扫描,,最多只返回一行数据, const 查询速度非常快, 它仅仅读取一次即可。 |
| eq_ref | 当使用了索引的全部组成部分,并且索引是PRIMARY KEY或UNIQUE NOT NULL 才会使用该类型 |
| ref | 当满足索引的最左前缀规则,或者索引不是主键也不是唯一索引时才会发生。如果使用的索引只会匹配到少量的行 |
| fulltext | 全文索引 |
| ref_or_null | 该类型类似于 ref,但是 MySQL 会额外搜索哪些行包含了 NULL。这种类型常见于解析子查询。 |
| index_merge | 此类型表示使用了索引合并优化,表示一个查询里面用到了多个索引 |
| unique_subquery | 该类型和 eq_ref 类似,但是使用了 IN 查询,且子查询是主键或者唯一索引 |
| index_subquery | 和 unique_subquery 类似,只是子查询使用的是非唯一索引 |
| range | 范围扫描,表示检索了指定范围的行,主要用于有限制的索引扫描。比较常见的范围扫描是带有BETWEEN子句或WHERE子句里有>、>=、<、<=、IS NULL、<=>、BETWEEN、LIKE、IN()等操作符 |
| index | 全索引扫描,和ALL类似,只不过index是全盘扫描了索引的数据。当查询仅使用索引中的一部分列时,可使用此类型 |
| ALL | 全表扫描,性能最差 |
Extra 额外信息说明
| 关键字 | 关键字 |
| Using where | 不用读取表中所有信息,仅通过索引就可以获取所需数据,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示 MySQL 服务器将在存储引擎检索行后再进行过滤。 |
| Using temporary | 表示 MySQL 需要使用临时表来存储结果集,常见于排序和分组查询,常见 group by,order by。 |
| Using filesort | 当 Query 中包含 order by 操作,而且无法利用索引完成的排序操作称为 “文件排序”。 |
| Using join buffer | 改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。 |
| Impossible where | 这个值强调了where语句会导致没有符合条件的行(通过收集统计信息不可能存在结果)。 |
| Select tables optimized away | 这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行。 |
| No tables used | Query语句中使用from dual 或不含任何from子句。 |
mysql> explain select * from student where id=12\G;*************************** 1. row ***************************id: 1select_type: SIMPLEtable: studentpartitions: NULLtype: const #只读取一次possible_keys: PRIMARYkey: PRIMARY #使用了主键索引key_len: 4ref: constrows: 1 #扫描了1条数据filtered: 100.00Extra: NULL1 row in set, 1 warning (0.00 sec)mysql> explain select * from student where name="wangwu"\G;*************************** 1. row ***************************id: 1select_type: SIMPLEtable: studentpartitions: NULLtype: ALL #全表扫描possible_keys: NULL #没有使用索引字段key: NULL #没有使用索引字段key_len: NULLref: NULLrows: 6 #扫描了6条数据,整个表就是6条数据filtered: 16.67Extra: Using where #在存储引擎检索行后再进行过滤1 row in set, 1 warning (0.00 sec)
1.4.6 profile 工具
开启 profiling 设置可以记录 SQL 语句执行的详细过程
mysql> select @@profiling;+-------------+| @@profiling |+-------------+| 0 |+-------------+1 row in set, 1 warning (0.00 sec)#无记录mysql> show profiles;Empty set, 1 warning (0.00 sec)#开启mysql> set profiling=1;Query OK, 0 rows affected, 1 warning (0.00 sec)#执行SQL语句mysql> select * from student where name="wangwu";+----+--------+------+--------+| id | name | age | gender |+----+--------+------+--------+| 12 | wangwu | 13 | M |+----+--------+------+--------+1 row in set (0.00 sec)#再次查看mysql> show profiles;+----------+------------+-------------------------------------------+| Query_ID | Duration | Query |+----------+------------+-------------------------------------------+| 1 | 0.00091900 | select * from student where name="wangwu" |+----------+------------+-------------------------------------------+1 row in set, 1 warning (0.00 sec)#删除索引mysql> drop index idx_name on student;Query OK, 0 rows affected (0.02 sec)Records: 0 Duplicates: 0 Warnings: 0#再次查询mysql> select * from student where name="wangwu";+----+--------+------+--------+| id | name | age | gender |+----+--------+------+--------+| 12 | wangwu | 13 | M |+----+--------+------+--------+1 row in set (0.01 sec)#两次用时对比mysql> show profiles;+----------+------------+-------------------------------------------+| Query_ID | Duration | Query |+----------+------------+-------------------------------------------+| 1 | 0.00091900 | select * from student where name="wangwu" || 2 | 0.01600600 | drop index idx_name on student || 3 | 0.00112750 | select * from student where name="wangwu" | #数据量太小,不能体现索引优势+----------+------------+-------------------------------------------+3 rows in set, 1 warning (0.00 sec)
导入大表再次对比
[root@rocky86 ~]# cat testlog.sqlcreate table testlog (id int auto_increment primary key,name char(10),salary int default 20);delimiter $$create procedure sp_testlog()begindeclare i int;set i = 1;while i <= 100000do insert into testlog(name,salary) values (concat('wang',FLOOR(RAND() * 100000)),FLOOR(RAND() * 1000000));set i = i +1;end while;end$$delimiter;
#导入[root@rocky86 ~]# mysql testdb < testlog.sqlmysql> use testdb;Database changedmysql> show tables;+------------------+| Tables_in_testdb |+------------------+| student || t1 || testlog |+------------------+3 rows in set (0.00 sec)mysql> select count(*) from testlog;+----------+| count(*) |+----------+| 0 |+----------+1 row in set (0.01 sec)#执行存储过程mysql> call sp_testlog;Query OK, 1 row affected (1 min 2.02 sec)mysql> select count(*) from testlog;+----------+| count(*) |+----------+| 100000 |+----------+1 row in set (0.01 sec)#查询mysql> select * from testlog limit 5;+----+-----------+--------+| id | name | salary |+----+-----------+--------+| 1 | wang64276 | 606675 || 2 | wang10506 | 705314 || 3 | wang21136 | 940888 || 4 | wang7034 | 529049 || 5 | wang43421 | 583940 |+----+-----------+--------+5 rows in set (0.00 sec)
#默认主键索引mysql> show index from testlog\G;*************************** 1. row ***************************Table: testlogNon_unique: 0Key_name: PRIMARYSeq_in_index: 1Column_name: idCollation: ACardinality: 98399Sub_part: NULLPacked: NULLNull:Index_type: BTREEComment:Index_comment:Visible: YESExpression: NULL1 row in set (0.00 sec)#查询mysql> select * from testlog where salary=583940;+----+-----------+--------+| id | name | salary |+----+-----------+--------+| 5 | wang43421 | 583940 |+----+-----------+--------+1 row in set (0.01 sec)#查看索引使用情况mysql> explain select * from testlog where salary=583940\G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: testlogpartitions: NULLtype: ALL #全表扫描possible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: 98399filtered: 10.00Extra: Using where1 row in set, 1 warning (0.00 sec)#查看执行时间mysql> show profiles;+----------+------------+-------------------------------------------+| Query_ID | Duration | Query |+----------+------------+-------------------------------------------+| 1 | 0.01881575 | select * from testlog where salary=583940 |+----------+------------+-------------------------------------------+1 row in set, 1 warning (0.00 sec)
#在salary列创建索引mysql> create index idx_salary on testlog(salary);Query OK, 0 rows affected (0.16 sec)Records: 0 Duplicates: 0 Warnings: 0#再次查询mysql> select * from testlog where salary=529049;+----+----------+--------+| id | name | salary |+----+----------+--------+| 4 | wang7034 | 529049 |+----+----------+--------+1 row in set (0.00 sec)#对比mysql> show profiles;+----------+------------+--------------------------------------------+| Query_ID | Duration | Query |+----------+------------+--------------------------------------------+| 1 | 0.01881575 | select * from testlog where salary=583940 || 2 | 0.15655150 | create index idx_salary on testlog(salary) || 3 | 0.00038900 | select * from testlog where salary=529049 |+----------+------------+--------------------------------------------+3 rows in set, 1 warning (0.00 sec)mysql> explain select * from testlog where salary=529049\G*************************** 1. row ***************************id: 1select_type: SIMPLEtable: testlogpartitions: NULLtype: refpossible_keys: idx_salarykey: idx_salarykey_len: 5ref: constrows: 1 #只扫描1条记录filtered: 100.00Extra: NULL1 row in set, 1 warning (0.00 sec)
相关文章:
MySQL 之INDEX 索引(Index Index of MySQL)
MySQL 之INDEX 索引 1.4 INDEX 索引 1.4.1 索引介绍 索引:是排序的快速查找的特殊数据结构,定义作为查找条件的字段上,又称为键 key,索引通过存储引擎实现。 优点 大大加快数据的检索速度; 创建唯一性索引,保证数…...
基于flask+vue的租房信息可视化系统
✔️本项目利用 python 网络爬虫抓取某租房网站的租房信息,完成数据清洗和结构化,存储到数据库中,搭建web系统对各个市区的租金、房源信息进行展示,根据各种条件对租金进行预测。 1、数据概览 将爬取到的数据进行展示ÿ…...
开源Web主机控制面板ISPConfig配置DNS
ISPConfig 是一个开源的 Web 主机控制面板,特别适合用于构建虚拟主机环境。 它拥有强大的 DNS 管理功能,可以: 管理 DNS 区域 (主区域、辅助区域)。支持多种记录类型。DNSSEC 支持。远程 DNS 服务器管理。 ISPConfig 优点在于专为主机服务设…...
【Python项目】信息安全领域中语义搜索引擎系统
【Python项目】信息安全领域中语义搜索引擎系统 技术简介:采用Python技术、MYSQL数据库等实现。 系统简介:系统主要是围绕着语义搜索展开的,要将输入的文字在爬取数据时能够通过深层次的内涵理解,来更好的查找到与之相关的精准信息…...
网站搭建基本流程
需求分析: 实现网站搭建的过程:首先进行网站的需求性分析 网站可分为前台系统和后台系统,由不同的功能拆分为不同的模块 如下是一个电商网站可以拆分出的模块: 在编写代码前,我们要先对网站进行架构,通过…...
mysql 存储空间增大解决方案
一:查询数据库中表占比比较多的表 SELECT table_name AS "Tables", round(((data_length index_length) / 1024 / 1024), 2) AS "Size (MB)" FROM information_schema.tables WHERE table_schema "自己的数据库名"; …...
深入解析队列与广度优先搜索(BFS)的算法思想:原理、实现与应用
目录 1. 队列的基本概念 2. 广度优先搜索(BFS)的基本概念 3. 队列在BFS中的作用 4. BFS的实现细节 5. C实现BFS 6. BFS的应用场景 7. 复杂度分析 8. 总结 1. 队列的基本概念 队列(Queue)是一种先进先出(FIFO, …...
Swap to Gather-----
C - 烟销日出不见人 问题陈述 给定一个长度为 NN 的字符串 SS,由 0 和 1 组成。保证 SS 至少包含一个 1。 您可以执行以下操作任意次数(可能为零): 选择一个整数 ii (1≤i≤N−11≤i≤N−1),并交换 SS 的第 ii 个和…...
使用DeepSeek+本地知识库,尝试从0到1搭建高度定制化工作流(自动化篇)
7.5. 配图生成 目的:由于小红书发布文章要求图文格式,因此在生成文案的基础上,我们还需要生成图文搭配文案进行发布。 原实现思路: 起初我打算使用deepseek的文生图模型Janus进行本地部署生成,参考博客:De…...
Python 函数式编程全攻略:从理论到实战的深度解析
本文深入剖析 Python 函数式编程,详细讲解其概念、核心特性(迭代器、生成器等)、内置函数及相关模块(itertools、functools ),结合丰富示例与直观图表,助力读者全面掌握函数式编程技巧ÿ…...
Ollama 在 LangChain 中的使用
文章目录 一、langChain 介绍二、环境安装1.依赖库安装2.下载模型 三、基本使用示例1.使用 ChatPromptTemplate 进行对话2.流式输出3.工具调用4.多模态模型调用 四、进阶使用1.使用 ConversationChain 进行对话2.自定义提示模板3.构建一个简单的 RAG 问答系统 五、遇到问题与解…...
使用apt-rdepends制作软件离线deb安装包
使用apt-rdepends制作软件离线deb安装包 除基础软件外,还要获取软件依赖包。 依赖包工具安装 apt-get install apt-rdependsapt-rdepends工具使用 使用apt-rdepends工具,递归方式分析软件依赖,下载软件包本体,和依赖包。制作时…...
根据POD名称生成 三部曲:get、describe、log、exec
#!/bin/bash# 定义颜色变量 RED\033[0;31m GREEN\033[0;32m YELLOW\033[0;33m NC\033[0m # No Color# 检查是否传入 Pod 名称作为参数 if [ -z "$1" ]; then# 如果没有传参,则提示用户输入 Pod 名称echo -e "${YELLOW}Please enter the Pod name:${…...
SQL sever数据导入导出实验
1.创建数据库TCP-H (1)右键“数据库”,点击“新建数据库”即可 (2)用sql语言创建,此处以创建数据库DB_test为例,代码如下: use master;go--检查在当前服务器系统中的所有数据里面…...
python环境的yolov11.rknn物体检测
1.首先是我手里生成的一个yolo11的.rknn模型: 2.比对一下yolov5的模型: 2.1 yolov5模型的后期处理: outputs rknn.inference(inputs[img2], data_format[nhwc])np.save(./onnx_yolov5_0.npy, outputs[0])np.save(./onnx_yolov5_1.npy, outpu…...
I2C、SPI、UART
I2C:串口通信,同步,半双工,双线(数据线SDA时钟线SCL),最大距离1米到几米 SPI(串行外设接口):串口通信,同步,全双工,四线&…...
如何监控和优化 MySQL 中的慢 SQL
如何监控和优化 MySQL 中的慢 SQL 前言一、什么是慢 SQL?二、如何监控慢 SQL?1. 启用慢查询日志启用方法:日志内容: 2. 使用 mysqldumpslow 分析日志 三、如何分析慢 SQL?1. 使用 EXPLAIN 分析执行计划使用方法&#x…...
13-二叉树最小深度-深度优先(DFS)
一、定义 什么是二叉树的最小深度? 二叉树的最小深度是指从根节点到最近的叶子节点的最短路径上的节点数。叶子节点是指没有子节点的节点。 举个例子: 1/ \2 3/ 4 这棵树的最小深度是 2,因为从根节点 1 到叶子节点 3 的路径最短&#x…...
51单片机入门_10_数码管动态显示(数字的使用;简单动态显示;指定值的数码管动态显示)
接上篇的数码管静态显示,以下是接上篇介绍到的动态显示的原理。 动态显示的特点是将所有位数码管的段选线并联在一起,由位选线控制是哪一位数码管有效。选亮数码管采用动态扫描显示。所谓动态扫描显示即轮流向各位数码管送出字形码和相应的位选ÿ…...
代码补全『三重奏』:EverEdit如何用上下文识别+语法感知+智能片段重构你的编码效率!
1 代码自动完成 1.1 应用场景 在编辑文档时,为了提高编辑效率,编辑器一般都会带有自动完成功能,比如:输入括号时自动补全另一半,输入文字时,自动补全剩下的部分。 1.2 使用方法 1.2.1 自动缩进 单击主菜…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...
