索引和sql优化

索引

索引分类

MySQL 数据库,将索引的具体类型主要分为以下几类:
分类 含义 特点 关键字
主键索引
针对于表中主键创建的索引
默认自动创建 , 只能 有一个,非空
primary
唯一索引
避免一个表中某数据列中的值重复
可以有多个
unique
常规索引
快速定位特定数据
可以有多个
全文索引
全文索引查找的是文本中的关键词,而不是比较索引中的值
可以有多个
fullText

 而在在InnoDB存储引擎中,根据索引的存储形式,又可以分为以下两种:

分类 含义 特点
聚集索引
将数据存储与索引放到了一块,索引结构的叶子
节点保存了行数据
必须有 , 而且只
有一个
二级索引
将数据与索引分开存储,索引结构的叶子节点关
联的是对应的主键
可以存在多个
聚集索引选取规则 :
如果存在主键,主键索引就是聚集索引。
如果不存在主键,将使用第一个唯一( UNIQUE )索引作为聚集索引。
如果表没有主键,或没有合适的唯一索引,则 InnoDB 会自动生成一个 rowid 作为隐藏的聚集索
引。
聚集索引和二级索引的具体结构如下:
索引和sql优化_第1张图片

具体过程如下:
①. 由于是根据name字段进行查询,所以先根据name='Arm'到name字段的二级索引中进行匹配查
找。但是在二级索引中只能查找到 Arm 对应的主键值 10。
②. 由于查询返回的数据是*,所以此时,还需要根据主键值10,到聚集索引中查找10对应的记录,最 终找到10对应的行row。
③. 最终拿到这一行的数据,直接返回即可。
回表查询: 这种先到二级索引中查找数据,找到主键值,然后再到聚集索引中根据主键值,获取 数据的方式,就称之为回表查询。

索引语法

创建索引:CREATE [ UNIQUE | FULLTEXT ] INDEX index_name ON table_name (index_col_name,... ) ;

查看索引:show index from 表名;

删除索引:drop index 索引名 on 表名;

SHOW INDEX FROM tb_user;
DROP INDEX user_phone ON tb_user;
CREATE UNIQUE INDEX user_phone1 ON tb_user(phone);
CREATE INDEX user_name ON tb_user(NAME);
CREATE INDEX user_age ON tb_user(age);
CREATE INDEX user_email ON tb_user(email);
CREATE INDEX user_pro_age_status ON tb_user(profession,age, STATUS);

 sql性能分析

sql执行频次

通过 show [session|global] status 命令可以提供服务器状态信息。 session 是查看当前会话 ,global 是查询全局数据 。
SHOW GLOBAL STATUS LIKE 'Com_______';   #全部
Com_delete: 删除次数
Com_insert: 插入次数
Com_select: 查询次数
Com_update: 更新次数
通过上述指令,我们可以查看到当前数据库到底是以查询为主,还是以增删改为主,从而为数据 库优化提供参考依据。 如果是以增删改为主,我们可以考虑不对其进行索引的优化。 如果是以 查询为主,那么就要考虑对数据库的索引进行优化了。

慢查询日志

慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10秒)的所有
SQL语句的日志,执行较快的SQL 是不会记录的。
1、查看慢查询日志是否开启(默认关闭):SHOW VARIABLES LIKE '%slow_query_log%';
索引和sql优化_第2张图片

slow_query_log:慢查询开启状态
slow_query_log_file:慢查询日志存放路径
2、如果为慢查询开启状态OFF表示关闭,开启慢查询日志:set global slow_query_log=1;
3、看慢查询的阈值(默认10秒):SHOW VARIABLES LIKE 'long_query_time%';
4、修改慢查询日志:SET long_query_time=3;

5、测试慢查询:select sleep(5);

6、查看执行了多少次慢查询:show global status like '%Slow_queries%';

7.查看慢查询日志

索引和sql优化_第3张图片

索引和sql优化_第4张图片

profile

show profiles 能够在做 SQL 优化时帮助我们了解时间都耗费到哪里去了
SELECT @@have_profiling ;#到当前MySQL是否支持profile操作
SELECT @@profiling ;  #查询profiling
SET profiling = 1;#开启profiling
SHOW PROFILES;#查看每一条SQL的耗时基本情况
SHOW PROFILE FOR QUERY query_id;#查看指定query_id的SQL语句各个阶段的耗时情况
SHOW PROFILE cpu FOR QUERY query_id;#查看指定query_id的SQL语句CPU的使用情况

explain

EXPLAIN 或者 DESC 命令获取 MySQL 如何执行 SELECT 语句的信息,包括在 SELECT 语句执行 过程中表如何连接和连接的顺序。
EXPLAIN SELECT 字段列表 FROM 表名 WHERE 条件 ;#直接在查询语句前面加上 EXPLAIN 或者 DESC。
索引和sql优化_第5张图片
Explain 执行计划中各个字段的含义:
字段 含义
id
select 查询的序列号,表示查询中执行 select 子句或者是操作表的顺序 (id相同,执行顺序从上到下; id 不同,值越大,越先执行 )
select_type
表示 SELECT 的类型,常见的取值有 SIMPLE (简单表,即不使用表连接 或者子查询)、PRIMARY (主查询,即外层的查询)、 UNION( UNION 中的第二个或者后面的查询语句)、 SUBQUERY( SELECT/WHERE 之后包含了子查询)等
type
表示连接类型,性能由好到差的连接类型为 NULL system const 、 eq_ref、 ref range index all
possible_keys
显示可能应用在这张表上的索引,一个或多个。
key
实际使用的索引,如果为 NULL ,则没有使用索引。
key_len
表示索引中使用的字节数, 该值为索引字段最大可能长度,并非实际使用长 度,在不损失精确性的前提下, 长度越短越好 。
rows
MySQL 认为必须要执行查询的行数,在 innodb 引擎的表中,是一个估计值, 可能并不总是准确的。
filtered
表示返回结果的行数占需读取行数的百分比, filtered 的值越大越好。

索引使用

最左前缀法则

指对于联合查询比如(profession,age, status),查询从索引的最左列开始,并且不跳过索引中的列。如果跳跃某一列,该列后面的索引将失效。

索引和sql优化_第6张图片索引和sql优化_第7张图片

最左前缀法则中指的最左边的列,是指在查询时,联合索引的最左边的字段(即是 第一个字段)必须存在,与我们编写SQL时,条件编写的先后顺序无关,如下所示。

范围查询

联合索引中,出现范围查询 (>,<) ,范围查询右侧的列索引失效。比如下面的status就失效了。

 当范围查询使用>= <= 时,索引是有效的。

索引失效情况

1、不要在索引列上进行运算操作, 索引将失效
索引和sql优化_第8张图片

 2、字符串类型字段使用时,不加引号,索引将失效。

索引和sql优化_第9张图片

3、如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。

索引和sql优化_第10张图片

索引和sql优化_第11张图片

4、用or分割开的条件, 如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。

 gender字段没索引

索引和sql优化_第12张图片

 5、如果MySQL评估使用索引比全表更慢,则不使用索引。

索引和sql优化_第13张图片

索引和sql优化_第14张图片

sql提示

删除前面的user_age和user_email索引。

执行 SQL ,创建 profession 的单列索引,

当执行SQL : explain select * from tb_user where profession = '软件工程';索引user_pro_age_status和idx_user_pro都可能被用到,取决于mysql的自动选择。

sql提示就是自己也可以指定使用哪个索引来达到优化操作的目的。

1、use index : 建议MySQL使用哪一个索引完成此次查询(仅仅是建议,mysql内部还会再次进
行评估)。

索引和sql优化_第15张图片
2、ignore index : 忽略指定的索引。


3、 force index : 强制使用索引。

索引和sql优化_第16张图片

覆盖索引

覆盖索引是指查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到。尽量使用覆盖索引,减少 select *。

从上述的执行计划我们可以看到,这三条 SQL语句的执行计划前面所有的指标都是一样的,都表示查找使用了索引,但后面的Extra不同,Using index表示是需要的数据都在索引列中能找到,所以不需要回表查询数据,Null表示需要回表查询数据,因为需要的数据并不是在索引列中都能找到。

前缀索引

当字段类型为字符串( varchar text longtext 等)时,有时候需要索引很长的字符串,这会让
索引变得很大,查询时,浪费大量的磁盘 IO , 影响查询效率。此时可以只将字符串的一部分前缀,建 立索引,这样可以大大节约索引空间,从而提高索引效率。
语法: create index idx_xxxx on table_name(column(n)) ;
eg:create index idx_email_5 on tb_user(email(5));

索引设计原则

1、针对于数据量较大,且查询比较频繁的表建立索引。
2、针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引。
3、尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
4、如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。
5、尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。
6、要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。
7、如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地用于查询。

sql优化

添加数据

需要一次性往数据库表中插入多条记录,可以从以下三个方面进行优化。
1、批量插入数据
Insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');

 2、手动控制事务

start transaction;
insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');
insert into tb_test values(4,'Tom'),(5,'Cat'),(6,'Jerry');
insert into tb_test values(7,'Tom'),(8,'Cat'),(9,'Jerry');
commit;

3、主键顺序插入,性能要高于乱序插入。  

大批量添加数据(比如: 几百万的记录),使用insert语句插入性能较低,此时可以使用MySQL数据库提供的load指令进行插入。操作如下:

-- 客户端连接服务端时,加上参数 -–local-infile
mysql –-local-infile -u root -p
-- 设置全局参数local_infile为1,开启从本地加载文件导入数据的开关
set global local_infile = 1;
加载数据形式如下:
load data local infile '/root/load_user_100w_sort.sql' into table tb_user fields terminated by ',' lines terminated by '\n' ;

索引和sql优化_第17张图片

主键优化

1、满足业务需求的情况下,尽量降低主键的长度。
2、插入数据时,尽量选择顺序插入,选择使用AUTO_INCREMENT自增主键。
3、尽量不要使用UUID做主键或者是其他自然主键,如身份证号。
4、业务操作时,避免对主键的修改。

order by优化

MySQL的排序,有两种方式:
Using filesort : 通过表的索引或全表扫描,读取满足条件的数据行,然后在排序缓冲区sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫 FileSort 排序。
Using index : 通过有序索引顺序扫描直接返回有序数据,这种情况即为 using index,不需要额外排序,操作效率高。
对于以上的两种排序方式,Using index的性能高,而Using filesort的性能低,我们在优化排序操作时,尽量要优化为 Using index。

测试:删掉之前user_age和user_phone1索引。

 创建索引:CREATE INDEX user_age_phone ON tb_user(age,phone);

排序时 , 也需要满足最左前缀法则 , 否则也会出现 filesort。

创建索引时,如果未指定顺序,默认都是按照升序排序的,而查询时,一个升序,一个降序,此时
就会出现 Using filesort

 为解决上面问题可创建以下索引:

create index idx_user_age_phone_ad on tb_user(age asc ,phone desc);

order by 优化规则总结:

1、 根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则。
2、 尽量使用覆盖索引。
3、 多字段排序 , 一个升序一个降序,此时需要注意联合索引在创建时的规则( ASC/DESC )。
4、 如果不可避免的出现 filesort ,大数据量排序时,可以适当增大排序缓冲区大小
sort_buffer_size( 默认 256k)

group by优化

1、 在分组操作时,可以通过索引来提高效率。
2、 分组操作时,索引的使用也是满足最左前缀法则的。

limit优化

在数据量比较大时,如果进行 limit 分页查询,在查询时,越往后,分页查询效率越低。
一般分页查询时,通过创建 覆盖索引 能够比较好地提高性能,可以通过覆盖索引加子查 询形式进行优化。
explain select * from tb_sku t , (select id from tb_sku order by id
limit 2000000,10) a where t.id = a.id;

count优化

count(字段) < count(主键 id) < count(1) ≈ count(*),所以尽量使用 count(*)。

update优化

I nnoDB的行锁是针对索引加的锁,不是针对记录加的锁 ,并且该索引不能失效,否则会从行锁
升级为表锁 。  

视频地址:

黑马程序员 MySQL数据库入门到精通,从mysql安装到mysql高级、mysql优化全囊括_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1Kr4y1i7ru/?spm_id_from=333.337.search-card.all.click&vd_source=282e51f661e6fc136b2286bee19b965c

你可能感兴趣的:(Redis,数据库,mysql)