mysql学习笔记-索引2

MySQL学习笔记-主键索引和二级索引 文章目录MySQL学习笔记-主键索引和二级索引1.笔记图2.索引的常见模型3.InnoDB 的索引模型4.主键索引和普通索引查询的区别5.如何选择主键字段6.笔记图7.回表过程8.最左前缀原则 MySQL学习笔记-主键索引和二级索引 在 MySQL 索引是为了提高查询效率的,但实现索引的的方式有很多,可以用于提高读写效率的数据结构也很多,常见的数据结构有哈希表、有序数组、搜索树,而 MySQL 中的索引又分为主键索引和二级索引,这篇文章就来学习一下 主键索引 和 二级索引。 1.笔记图 2.索引的常见模型 阅读详情

----------------------------------索引-----------------------------------
mysql官方对索引的定义:

索引(Index)是帮助mysql高效获取数据的数据结构===>索引的本质:索引是数据结构

索引是排好序的快速查找数据结构

一般索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上

平时所说的索引,如果没有特别指明,都是指B树(多路搜索树,并不一定是二叉的)结构组织的索引,其中聚集索引,次要索引,覆盖索引,复合索引,前缀索引,唯一索引默认都是B+树索引,统称索引。当然,除了B+树赭红类型的索引外,还有哈希索引(hash index)等

数据本身之外,数据库还维护着一个满足特定查找算法的数据结构。这些数据结构以某种方式指向数据,这样就可以在这些数据结构的基础上实现高级查找算法。这种数据结构就是索引。

索引的优势

①类似大学图书馆建书目索引,提高数据检索效率,降低数据库的IO成本
②通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗

索引的劣势

①实际上索引也是一张表,该表保存了主键和索引字段,并指向实体表的记录,所以索引也要占用空间
②虽然索引大大提高查询速度,但同时降低了更新表的速度,如对表进行insert update 和detele.因为更新表。mysql不仅要保存数据还要保存一下索引文件每次更新添加索引列的字段,都会调整因为更新所带来的键值变化后的索引信息
③索引只是提高效率的一个因素,如果mysql有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询,索引建立不是一朝一夕的。

索引分类
单值索引

一个索引只包含单个列,一个表可以有多个单列索引

唯一索引

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

复合索引

一个索引包含多个列

基本语法
①创建

create [unique] index indexName on tableName(columnName...);
alter tableName add [unique] index [indexName] on (columnName...)

②删除索引

drop index [indexName] on tableName;

③查看索引

show index from tableName \G;

④使用alter命令添加数据表的索引

alter table tableName add primary key(column_list); //添加主键 ,意味着索引值必须是唯一的,且不能为null
alter table tableName add unique index_name(column_list); //创建的索引值必须是唯一的(除了null外,null可能出现多次)
alter table tableName add index index_name(column_list); //添加普通索引,索引值可出现多次
alter table tableName add  fullText index_name(column_list); //该语句指定了索引为fullText,用于全文索引

mysql索引结构
①BTree索引–索引原理
②Hash索引
③full-text全文索引
④R-Tree索引

哪些情况需要创建索引
①主键自动建立唯一索引
②频繁作为查询条件的字段应该创建索引
③查询中与其他表关联的字段,外键关系建立索引
④频繁更新的字段不适合创建索引,因为每次更新除了更新记录还会更新索引,加重IO负担
⑤where条件里用不到的字段不创建索引
⑥单键/组合索引选择问题:高并发下倾向于创建组合索引
⑦查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
⑧查询中统计或者分组字段需要创建索引

不创建索引的情况
①表记录太少,通常再300万条数据之前,mysql查询速度还是可以的,此时不需要创建索引,300万数据之后性能开始下降
②经常增删改的表:建立索引提高查询速度,同时却降低更新表的速度,如对表进行insert , update,delete,同时因为更新表时,mysql不仅要保存数据,还要保存索引文件
③注意,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果

假如一个表有10万行记录,有一个字段A只有T和F两种值,且每个值的分布概率大约为50%,那么对这种表A字段建索引一般不会提高数据库的查询速度。
索引的选择性是指,索引列中不同值的数目与表中记录数的比。如果一个表中有2000条记录,表索引列有1980个不同的值,那么这个索引的选择性就是1980/2000=0.99,一个索引的选择性越接近1,这个索引的效率就越高。

mysql性能分析
①Mysql Query Optimizer(mysql查询优化器)

1 mysql中有专门负责优化select语句的优化器模块,主要功能:通过计算分析系统中收集到的统计信息,为客户端请求的query提供他认为最优的执行计划(他认为最优的数据检索方式不一定是DBA认为最优的,这部分最耗费时间)
2 当客户端向mysql请求一条query,命令解析器模块完成请求分类,区别出是select并转发给mysql query optimizer时,mysql query optimizer首先会对整条query进行优化,处理掉一些常量表达式的预算,直接换算成常量值。并对query中的查询条件进行简化和转换,如去掉一些无用或显而易见的条件,结构调整等。然后分析query中Hint信息(如果有),看显示Hint信息是否可以完全确定该query的执行计划。如果没有Hint或Hint信息还不足以完全确定执行计划,则会读取所涉及对象的统计信息,根据query进行写相应的计算分析,然后再得出最后的执行计划

②mysql常见性能瓶颈:

1 CPU:CPU饱和一般发生在数据装入内存或从磁盘上读取数据的时候
2 IO: 磁盘I/O瓶颈发生在装入数据远大于内存容量的时候
3 服务器硬件的性能瓶颈:top , free , iostat 和 vmstat 来查看系统的性能状态

③explain关键字
1 是什么

使用explain关键字可以模拟优化器执行sql查询语句,从而知道mysql是如何处理你的sql语句的。分析查询语句或表结构的性能瓶颈(结合mysql官网查看)
https://dev.mysql.com/doc/refman/5.7/en/execution-plan-information.html

2 能做什么

①表的读取顺序
②数据读取操作的操作类型
③那些索引可以使用
④那些索引被实际使用
⑤表之前的引用
⑥每张表有多少行被优化器查询

3如何使用

explain + sql语句
执行计划包含的信息

+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+

名字段解释
一 id
①select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
②三种情况:
id相同,执行顺序由上至下
id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
id相同不同,同时存在,id值越大,优先级越高,越先被执行,id相同仍然按照从上至下执行的原则 derived表示衍生 表示衍生的表其id为2

二 select_type
①有哪些

1 SIMPLE
2 PRIMARY
3 SUBQUERY
4 DERIVED
5 UNION
6 UNION RESULT

②查询的类型,主要是用于区别普通查询,联合查询,子查询等的复杂查询

1 SIMPLE 简单的select查询,查询中不包含子查询或union
2 PRIMARY 查询中若包含任何复杂的子部分,最外层查询则被标记为PRIMARY
3 SUBQUERY 在select或where列表中包含了子查询
4 DERIVED 在from列表中包含的子查询被标记为DERIVED(衍生) mysql会递归执行这些子查询,把结果放在临时表里
5 UNION 若第二个select出现在UNION之后,则被标记为UNION 若UNION包含早在from子句的子查询中,外层select将被标记为DERIVED
6 UNION RESULT 从UNION表获取结果的select

type
①访问类型排列

type显示的是访问类型,是较为重要的一个指标。结果值从好到坏依此是
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > range > index > ALL
一般来说,得保证查询至少达到range级别,最好能达到ref

②显示查询使用了何种类型

1 system : 表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,这个也可以忽略不计。(system经过尝试就算建一张一个字段的表,也出现不了system的查询类型,mysql版本为5.7,就算将id作为主键,并最为查询条件(where后) type类型就是const)
2 const : 表示通过索引一次就找到了,const用于比较primary key或者unique索引。因为只匹配一行数据,所以很快。如将主键置于where列表中,mysql就能将该查询转换为一个常量
3 eq_ref : 唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描
4 ref 非唯一性索引扫描,返回匹配某个单独值的所有行。本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以它应该属于查找和扫描的混合体
5 range : 只检索给定范围的行,使用一个索引来选择行。key列显示使用那个索引。一般就是在where语句中出现了between , < , < , in等的查询。这种范围扫描索引扫描比全表扫描好,因为它只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引。
6 index : full index scan, index与all区别为index类型只遍历索引树。这通常比all快,因为索引文件通常比数据文件小。(也就是虽然all和index都是读全表,但index是从索引中读取,而all是从硬盘中读)
7 all : full table scan ,将遍历全表以找到匹配的行
备注:一般来说,得保证查询至少达到range级别,最好能达到ref.

possible_keys

显示可能应用在这张表中的索引,一个或多个。
查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用

key

实际使用的索引。如果为null,则没有使用索引
查询中若使用了覆盖索引,则该索引仅出现在key列表中

key-len

表示索引中使用的字符,可通过该列计算查询中使用的索引长度。在不损失精确性的情况下,长度越短越好
key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不得通过表内检索出的

ref

显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值

rows

根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数

extra

包含不适合在其他列中显示但十分重要的额外信息
1 Using filesort : 说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序读取,mysql中无法利用索引完成的排序操作称为“文件排序”;(使用group by的字段最好和所建索引的顺序和数目一致,否则容易产生文件内排序filesort 以及 使用临时表)
2 Using temporary : 使用临时表保存中间结果,mysql在对查询结果排序时使用临时表。常见于排序order by 和 分组查询 group by;
3 Using index : 表示相应的select操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错
如果同时出现using where,表明索引被用来执行索引键值的查找;
如果没有同时出现using where,表明索引用来读取数据而非执行查找动作
4 Using where 表明使用了where过滤
5 using join buffer : 使用了连接缓存,说明配置文件中的join buffer可以调大一些
6 impossible where : where子句的值总是false(相当于一个字段既要求是男 又要求同时是女),不能用来获取任何元组
7 select tables optimized away : 在没有group by 子句的情况下,基于索引优化min/max操作或者对于mysql存储引擎优化count(*)操作,不必等到执行阶段在进行计算,查询执行计划生成的阶段即完成优化
8 distinct : 优化distinct操作,在找到第一个匹配的元组后即停止找同样值的操作

索引优化案例
一 单表索引所优化案例

# 建表
drop table if exists article;
create table article(
	id int primary key auto_increment ,
	author_id int not null,
	category_id int not null,
	views int not null,
	comments int not null,
	title varchar(255) not null,
	content text not null
);

#插入数据
insert into article (author_id,category_id,views,comments,title,content) values
(1,1,1,1,'1','1'),
(2,2,2,2,'2','2'),
(1,1,3,3,'3','3');

##查询
mysql> select * from article;
+----+-----------+-------------+-------+----------+-------+---------+
| id | author_id | category_id | views | comments | title | content |
+----+-----------+-------------+-------+----------+-------+---------+
|  1 |         1 |           1 |     1 |        1 | 1     | 1       |
|  2 |         2 |           2 |     2 |        2 | 2     | 2       |
|  3 |         1 |           1 |     3 |        3 | 3     | 3       |
+----+-----------+-------------+-------+----------+-------+---------+

#查询category_id为1 且 comments > 1 的情况下,views最多的article_id
mysql> select id,author_id from article where category_id = 1 and comments > 1 order by views desc limit 1;
+----+-----------+
| id | author_id |
+----+-----------+
|  3 |         1 |
+----+-----------+

#使用explain分析这条sql,可以看到type为ALL,意味着全表扫描,extra信息显示using filesort,文件内排序,可以看出这是一条性能低下的sql,因此需要优化
mysql> explain select id,author_id from article where category_id = 1 and comments > 1 order by views desc limit 1;
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                       |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
|  1 | SIMPLE      | article | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |    33.33 | Using where; Using filesort |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+

#通常在where中查询的字段需要建立索引,先尝试为where后面用到的三个字段建立联合索引,看看效果如何
create index article_ccv on article(category_id,comments,views);

#再来看一下分析结果,可以看到type变成了range,范围查找,解决了之前全表扫描的问题,并且使用到了索引,但是仍然可以看到extra中依然使用到了filesort,因此依然没有解决文件内排序的问题。现在是建的联合索引,comments在联合索引的中间,此sql中comments为一个范围,这样的话views就不能使用索引进行查找了,因此考虑跳过comments字段,重新建立category_id和views的联合索引,看一下是否性能更加优越
mysql> explain select id,author_id from article where category_id = 1 and comments > 1 order by views desc limit 1;
+----+-------------+---------+------------+-------+---------------+-------------+---------+------+------+----------+---------------------------------------+
| id | select_type | table   | partitions | type  | possible_keys | key         | key_len | ref  | rows | filtered | Extra                                 |
+----+-------------+---------+------------+-------+---------------+-------------+---------+------+------+----------+---------------------------------------+
|  1 | SIMPLE      | article | NULL       | range | article_ccv   | article_ccv | 8       | NULL |    1 |   100.00 | Using index condition; Using filesort |
+----+-------------+---------+------------+-------+---------------+-------------+---------+------+------+----------+---------------------------------------+

#删除之前建的联合索引
drop index article_ccv on article;

#重建联合索引
create index article_cv on article(category_id,views);

#再次查看sql的分析情况,可以看到type变成了ref(非唯一性索引扫描),这个级别效率已经很高了,使用到了索引,然后extra列的信息显示已经没有在使用filesort了,说明已经不在进行文件内排序,因此性能较之前的sql相比有了很大的提升
mysql> explain select id,author_id from article where category_id = 1 and comments > 1 order by views desc limit 1;
+----+-------------+---------+------------+------+---------------+------------+---------+-------+------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key        | key_len | ref   | rows | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | article | NULL       | ref  | article_cv    | article_cv | 4       | const |    2 |    33.33 | Using where |
+----+-------------+---------+------------+------+---------------+------------+---------+-------+------+----------+-------------+

二 两表索引优化案例

#建表
drop table if exists `class`;
create table `class`(
	id int primary key auto_increment,
	card int not null
);

drop table if exists books;
create table books(
	bookId int primary key auto_increment,
	card int not null
);

#插入数据 两表均插入20条随机数据,这样的话能保证会出现左表有的右边没有,反之亦然。
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `class`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));
insert into `books`(card) values(floor(1 + (rand()*20)));

#先不建索引的情况下左连接的性能分析,可以看到两表均为全表扫描,并且可能查询的行数均为20条
mysql> explain select * from class left join books on class.card = books.card;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                              |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | class | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   20 |   100.00 | NULL                                               |
|  1 | SIMPLE      | books | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   20 |   100.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+

#对于左连接,目前不知道是在左表字段建索引好还是在右表字段建索引好,因此可以先在左表字段建,看看效果,大胆假设,小心求证
alter table class add index idx_class_card(card);

#查看sql的性能分析,可以看到对于添加索引的表type变成了index,其余不变,得到了一定的优化
mysql> explain select * from class left join books on class.card = books.card;
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type  | possible_keys | key            | key_len | ref  | rows | filtered | Extra                                              |
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | class | NULL       | index | NULL          | idx_class_card | 4       | NULL |   20 |   100.00 | Using index                                        |
|  1 | SIMPLE      | books | NULL       | ALL   | NULL          | NULL           | NULL    | NULL |   20 |   100.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+----------------------------------------------------+

#再来看下在右表建索引的情况
#删除左表索引
drop index idx_class_card on class;
#创建右表索引
create index idx_books_card on books(card);

#查看sql性能分析,可以看到右表的type变成了ref,另外可能查询的行数也明显减少,变成1,因此在左连接中,在右表字段创建索引,性能优化的更多
mysql> explain select * from class left join books on class.card = books.card;
+----+-------------+-------+------------+------+----------------+----------------+---------+-----------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys  | key            | key_len | ref             | rows | filtered | Extra       |
+----+-------------+-------+------------+------+----------------+----------------+---------+-----------------+------+----------+-------------+
|  1 | SIMPLE      | class | NULL       | ALL  | NULL           | NULL           | NULL    | NULL            |   20 |   100.00 | NULL        |
|  1 | SIMPLE      | books | NULL       | ref  | idx_books_card | idx_books_card | 4       | test.class.card |    1 |   100.00 | Using index |
+----+-------------+-------+------------+------+----------------+----------------+---------+-----------------+------+----------+-------------+

#以上现象的原因:这是由左连接的特性决定的,left join条件用于确定如何从右表搜索行,左表的数据一定都有,所以右边是我们的关键点,一定需要建立索引。
#同理,右连接时(right join),该查询条件用于确定如何从左表搜索行,因此左表一定需要建立索引。

三表连接索引优化

三表查询索引优化

#建表
drop table if exists phone;
create table phone(
	phoneId int primary key auto_increment,
	card int not null
);

#插入数据
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));
insert into phone(card) values(floor(rand()*20 + 1));

#三表连接sql分析,三张表的type均为全扫描,根据上面的结果,针对左连接,对右表查询字段建立索引
mysql> explain select * from class left join books on class.card = books.card left join phone on books.card = phone.card;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                              |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | class | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   20 |   100.00 | NULL                                               |
|  1 | SIMPLE      | books | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   20 |   100.00 | Using where; Using join buffer (Block Nested Loop) |
|  1 | SIMPLE      | phone | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   20 |   100.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+

#建立索引
create index idx_books_card on books(card);
create index idx_phone_card on phone(card);

#sql性能分析,可以看到建立索引的表type变成了ref,使用到了索引,并且行数减小至1行,优化效果较好 ===> 索引最好设置在需要经常查询的字段中
mysql> explain select * from class left join books on class.card = books.card left join phone on books.card = phone.card;
+----+-------------+-------+------------+------+----------------+----------------+---------+-----------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys  | key            | key_len | ref             | rows | filtered | Extra       |
+----+-------------+-------+------------+------+----------------+----------------+---------+-----------------+------+----------+-------------+
|  1 | SIMPLE      | class | NULL       | ALL  | NULL           | NULL           | NULL    | NULL            |   20 |   100.00 | NULL        |
|  1 | SIMPLE      | books | NULL       | ref  | idx_books_card | idx_books_card | 4       | test.class.card |    1 |   100.00 | Using index |
|  1 | SIMPLE      | phone | NULL       | ref  | idx_phone_card | idx_phone_card | 4       | test.books.card |    1 |   100.00 | Using index |
+----+-------------+-------+------------+------+----------------+----------------+---------+-----------------+------+----------+-------------+

总结:

对于join语句的优化,尽可能减少join语句中的NestedLoop的循环总次数:永远用小结果集驱动大的结果集
优先优化NestedLoop的内层循环
保证join语句中被驱动表上join条件字段已经被索引
当无法保证被驱动表的join条件字段被索引且内存资源充足的前提下,不要太吝啬joinBuffer的设置

在以上的所有的名字段中最为重要的有五个:

id type key rows extra

覆盖索引(Covering index)

理解方式一
select的数据列只从索引中就能够取得,不必读取数据行,mysql可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件,换句话说查询列要被所建索引覆盖
理解方式二
索引是高效找到行的一个方法,但是一般数据库也能使用索引找到一个列的数据,因此不必读取整个行。毕竟索引叶子节点存储了他们索引的数据;当能通过读取索引就可以获取想要的数据,那就不需要读取行了。一个索引包含(或覆盖了)满足查询结果的数据就叫做覆盖索引。
注意:
如果要使覆盖索引,一定要注意select列表中只取出需要的列,不可select*,因为如果将所有字段一起做索引会导致索引文件过大,查询性能降低。

聚集索引和非聚集索引
聚集索引

非聚集索引

allegro转AD-(附工具) 本文介绍了将Allegro的.brd文件转换为Altium Designer可用的.alg文件的操作流程。首先需要下载专用转换工具,然后通过运行.bat脚本将.brd文件转换为.alg格式。最后在Altium Designer中使用导入向导完成文件转换,生成可用的PCB设计文件。整个过程简单快捷,只需三个步骤即可实现Allegro到Altium Designer的工程文件转换。 阅读详情

相关推荐

智能客服系统知识库数据清洗

数据清洗(Data Cleaning)是确保智能客服知识库高效运行的重要环节,主要涉及。| 分类 & 标签优化 | 重新组织 FAQ,创建关键字索引 || 定期更新 | 结合用户反馈,每 1-3 个月优化 |才能提供更优质、正确的回答,提升客户满意度!、Zendesk、Intercom 等)中,: FAQ 或客服回答中可能存在。,会影响 AI 匹配的准确性。是一个持续优化的过程,

z1941563559的博客 2098

MySQL学习笔记:索引2

MySQL45讲》

山鬼谣的专栏 529

从智能家居到智慧城市:AI Agent Harness Engineering 作为统一控制中枢

我们可以把每个独立的智能系统看作一根带有独立功能的电线:智能家居Agent是负责家庭设备控制的电线,社区Agent是负责社区管理的电线,城市交通Agent是负责交通调度的电线,而AHE就是把这些分散的电线整合起来的「智能线束」:它不仅负责把不同接口、不同协议、不同层级的Agent连接起来,还提供统一的编排、调度、协同、观测能力,实现全局效用最大化的智能决策。

AI Agent Harness Engineering 201

MySQL学习笔记2---MySQL索引

2、MySQL索引 2.1、数据结构及算法基础 2.1.1、索引的本质 MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。提取主干即可得到索引的本质:索引是一种数据结构。 数据库查询是数据库的最主要功能之一。我们都希望查询数据的速度能尽可能的快,因此数据库系统的设计者会从查询算法的角度进行优化。例如二分查找(binary search)、二叉树查找(binary tree search)等。但是如果稍微分析一下会发现,每种查找算法都只能应用于特定的数据结构之上,例如二分

小宇哥x的博客 234

LMI线性矩阵不等式之非线性变量处理

​ 如果一个LMI线性矩阵不等式中的某项存在两个矩阵变量相乘,那么称该类情形为非线性矩阵不等式,而要直接求解时很困难的,而且LMI工具箱也无法求解非线性矩阵,所以需要通过变量替换法进行处理。 ​...

Mr.邹的博客 4549

把 300 亿参数的 Qwen3-30B-A3B 塞进 16GB 手机:MoE、mmap 与内存轮转的完整拆解

这篇文章详细拆解了如何在16GB内存手机上运行305亿参数的Qwen3-30B-A3B大模型。作者通过MoE(专家混合)架构、内存映射(mmap)和专用NPU内存(rpcmem)的巧妙结合实现了这一"不可能"的任务。 核心原理在于:MoE模型将庞大的前馈网络拆分为128个专家,每个词只激活8个专家,97%的权重处于闲置状态;通过mmap技术按需加载当前需要的专家权重;同时利用NPU专用内存高效计算关键部分。三个关键开关(GGML_HEXAGON_MOE_PAGING=1、--mmap、GGML_CPU_RE

q742971636的博客 185

MySQL学习笔记(2)——索引

索引简介 是什么: 帮助MySQL高效获取数据的数据结构(B树结构) 目的: 1、提高查询效率 2、为字段排序 缺点: 降低了insert、update、delete的速度。因为不仅仅要保存数据,还要更新索引。 索引分类 单值索引: 一个索引是一个单列(数据库表中的一列),一个表中可以有多个单列索引。 唯一索引: 索引列的值必须唯一,但可以为null。 复合索引: 一个索引包含了多个列。 ...

sam的博客 1236

VisionMaster脚本调试(VS)

使用VS调试VisionMaster 脚本

yu_fujiang的专栏 3292

Mysql学习笔记2: 索引优化分析

文章目录第 2 章 索引优化分析1、慢 SQL2、join 查询2.1、SQL 执行顺序2.2、JOIN 连接查询3、索引简介3.1、索引是什么3.2、索引原理3.3、索引优劣势3.4、MySQL 索引分类3.5、MySQL 索引语法3.6、MySQL 索引结构3.6.1、Btree 索引3.6.2、B+tree 索引3.7、何时需要建索引4、性能分析4.1、性能优化概述4.2、Explain 概述4.3、Explain 详解5、索引优化5.1、单表索引优化5.2、两表索引优化5.3、三表索引优化6、索引失

qq_45376627的博客 985

全志 camera: 4路AHD摄像头转MIPI

TP2815 驱动模块主要实现将 4 路的 AHD/TVI/CVBS Camera 的数据转换为 MIPI 数据,从而实现在 T527 端来对数据进行处理和送显。

Linux驱动开发工程师,熟悉Linux/Android底层驱动、TP、显示、IIC、网络等通用外设调试适配,Linux上层应用开发。常用平台瑞芯微、全志、恩智浦等。 9086

abapGit 安装与初始化完整指南:从 on-premise 到 SAP BTP ABAP environment 的一条龙实践

本文为ABAP开发者提供abapGit从安装到团队协作的完整指南。内容涵盖社区版ZABAPGIT的on-premise安装、Eclipse ADT插件配置、BTP环境使用及常见网络问题处理。重点包括:获取最新构建的安装步骤、EN语言环境的重要性、ADT插件安装方法、以及如何实现on-premise与BTP间的代码迁移。文中特别强调企业环境下代理设置、证书配置等注意事项,并提供实际操作案例,如将RAP业务对象迁移到BTP环境。文末附有可复用的实施清单,帮助开发者快速落地abapGit。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 412

MySQL 学习笔记2——存储引擎、索引、事务

MySQL 学习笔记2——存储引擎、索引、事务 存储引擎 定义:一个数据文件的存储机制 MyISAM 不支持外键 不支持事务 支持全文索引 表锁 InnoDB 支持外键 支持事务 不支持全文索引 行锁 MEMORY varchar类型当作char类型(提高效率) 不支持大文本字段和图片类型 ARCHIVE 索引 事务 定义:满足ACID四个特性则称为事务。 ...

一个代码小白的进阶之路 333

C#上位机实战:PLC与检测设备无缝对接,构建产品质量实时判定系统

本文分享了基于C#开发的汽车零部件质量检测系统实现经验。系统采用三层架构:设备层(PLC/视觉相机/三坐标)、通信层(OPC UA/SDK/串口)和应用层(数据采集/判定/存储)。重点解决了三大技术难点:1)通过OPC UA订阅模式将PLC通信延迟从500ms降至50ms;2)反编译厂商Demo破解视觉SDK对接难题;3)采用时间戳+产品ID实现多设备数据同步。系统上线后质检人员减少67%,误判率降至0.5%,数据追溯效率显著提升。文章强调工业场景下稳定性优先于技术复杂度,实用经验值得借鉴。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 799

mysql学习笔记(2)-创建MySQL索引

1. 单列索引 创建语法: ALTER TABLE ADD PARIMARY KEY [index-name] (); ALTER TABLE ADD [UNIQUE]  KEY|INDEX [index-name] (); 删除语法: DROP INDEX [index-name] ON ; 2.  索引的作用: 1)限制查询读取的行数 上述查询中ty

呵呵哈哈 492

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

MySQL 学习笔记2.1 索引介绍及常用操作

索引的定义 官方定义: 索引(Index)是帮助MySQL高效获取数据的 数据结构。 简单理解: 简单地来说,就是 排好序的快速查找数据结构。 索引的目的 在于 提高查询效率,可以类比字典。比如查询“admin”这个单词,先定位到a,然后依次定位查找。 ...

qq_41923058的博客 174

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

mysql学习笔记-索引优化【2】-索引实际案例分析

测试数据 CREATE TABLE test03 ( id INT PRIMARY KEY NOT NULL auto_increment, c1 CHAR (10), c2 CHAR (10), c3 CHAR (10), C4 CHAR (10), c5 CHAR (10) ); insert into test03(c1,c2,c3,c4,c5) values('a1','a2','a3','a4','a5'); insert into test03(c1 ,c2,c3,c4, c5) v

weixin_39236708的博客 200

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

尚硅谷MySQL高级学习笔记 -- 2.索引优化分析

1、慢 SQL 性能下降、 SQL 慢、执行时间长、等待时间长的原因分析 查询语句写的烂索引失效: 单值索引:在user表中给name属性建个索引,create index idx_user_name on user(name)复合索引:在user表中给name、email属性建个索引,create index idx_user_nameEmail on user(name,email) 关联查询太多join(设计缺陷或不得已的需求)服务器调优及各个参数设置(缓冲、线程数等) 2、jo

exodus3的博客 1万+

高性能MYSQL(学习笔记)-索引篇2

 高性能的索引策略高效的选择和使用索引有很多种方式,其中有些是针对特殊案例的优化,有些则是针对行为的优化,接下来介绍如何高效的使用索引。独立的列我们通常会看到一些查询不当的索引,如果查询的列不是独立的,则MYSQL就不会使用索引。独立的列指的是所以不能是表达式的一部分,也不能是函数的参数例如:wher actor_id+1=5 to_days(current_date)-to_days(date_...

qq_27661911的博客 734

[MySQL学习笔记] 索引

MySQL索引是提高查询效率的关键数据结构,主要采用优化的B+Tree结构,相比二叉树和B-Tree具有层次浅、检索快、支持范围查询等优势。索引分为聚集索引和二级索引,但使用不当会导致失效,如违反最左前缀法则、范围查询、运算操作等情况。通过慢查询日志、explain等工具可分析SQL性能。索引使用原则包括:对高频查询表建索引、选择高区分度字段、控制索引数量、优先使用联合索引等。合理使用索引能显著提升查询效率,但需注意索引会占用存储空间并影响写操作性能。

qq_58547683的博客 1073

【MySQL学习笔记】关于索引

索引下推是MySQL5.6的优化机制,默认是开启的,如果条件判断字段,在二级索引B+树里,就会下推到InnoDB存储引擎层来过滤,过滤完的记录,才会回表,相比没有索引下推的时候,可以减少回表次数。InnoDB会使用主键索引在B+树维护索引和数据文件,创建的联合索引也会生成一个索引树,同样都是B+树的结构,只不过它的data部分存储的是联合索引所在行的值。所以说,联合索引的优势在于支持索引覆盖查询,避免回表操作,并且对索引列的查询可直接利用索引的有序性完成排序,无需额外的外部排序,显著提升查询性能。

席万里的博客 1014

MySQL系列之索引知识学习笔记

继我的上篇博客:Oracle索引知识学习笔记之后,再记录一篇MySQL的索引知识学习笔记,本博客是我在学习尚硅谷的学习教程后,做的笔记,当然我不是为了所谓宣传,仅仅是学习记录的笔记,本来可以不分享出来,分享出来的目录仅仅可以给网上的学习者参考学习,同时写在csdn比较方便,支持图片上传,也方便自己以后查找复习 文章目录一、索引的概念二、索引分类三、索引用法四 、索引架构简介五、索引适用的情况六、索...

Nicky's blog 3886

【MySQL】-14 MySQL索引(上篇MySQL索引类型前置-2-高性能的索引策略)

MySQL索引-高性能的索引策略

yinying293的博客 1472

MySQL学习[2] ——MySQL索引

通过将多个字段组合成一个索引,这个索引就叫做联合索引。联合索引的非叶子节点用两个字段的值作为 B+Tree 的 key 值。当在联合索引查询数据时,先按 product_no 字段比较,在 product_no 相同的情况下再按 name 字段比较。这是**最左匹配原则,按照最左优先的方式进行索引的匹配。在使用联合索引进行查询的时候,如果不遵循「最左匹配原则」,联合索引会失效**,这样就无法利用到索引快速查询的特性了。

shenfenxihuan的博客 5173

MYSQL学习笔记:索引

叶子节点上存储了所有的key值和对应的data,搜索每个节点最后都要到叶子节点上。非叶子节点只存储key不存储data,每个节点存储的key个数更多,理论上来讲层数更低,搜索效率更高。自适应hash索引的维护也是要耗费性能的,不是所有情况下都可以提升二级索引的查询性能。最理想的情况是一次磁盘IO读取的磁盘块内容刚好存储在B树的一个节点中。原来是先找到二级索引,然后在通过二级索引找到主键再搜索得到数据页。反之,innoDB的那种数据索引不分离的方式就算聚集索引。物理上分为聚集索引和非聚集索引。

weixin_45934869的博客 1218

【MySQL】索引

【MySQL】索引。本期【MySQL】讲解MySQL中索引的概念,什么是索引,为什么要有索引,以及MySQL如何做到和磁盘交互,使得数据持久化,还将会展示MySQL索引的相关操作。

jupangMZ的博客 2221

【MySQL学习笔记】MySQL的索引

索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。索引的优点:1- 提高数据检索的效率,降低数据库的IO成本;2- 通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗。索引的缺点:1- 索引列也是要占用空间的。

wrjwww的博客 891
上一篇: mysql学习笔记-索引1
下一篇: hivesql面试题-两个List转多行并一一匹配(posexplode函数)
programmer_trip
博客等级 码龄7年 3187粉丝 81原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值