MYSQL的SQL优化

insert语句

开启事务

手动控制事务

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;

内存插入

load命令中用 fields terminated by ','lines terminated by '\n' 参数来指定字段和行的分隔符 

-- 客户端连接服务端时,加上参数 -–local-infile
mysql –-local-infile -u root -p
-- 设置全局参数local_infile为1,开启从本地加载文件导入数据的开关
set global local_infile = 1;
-- 执行load指令将准备好的数据,加载到表结构中,
load data local infile 'tb_sku1.sql' into table `tb_sku` fields terminated by ',' lines terminated by '\n';

要导入的数据

连接数据库 

MYSQL的SQL优化_第1张图片

 set global local_infile = 1;开启本地导入数据

MYSQL的SQL优化_第2张图片

 show global variables like 'local_infile';查看是否为on开启状态

MYSQL的SQL优化_第3张图片

load data local infile 'tb_sku1.sql' into table `tb_sku` fields terminated by ',' lines terminated by '\n'; 执行成功(window系统推荐在tb_sku1.sql文件目录下执行,否则会显示(OS errno 2 - No such file or directory)

MYSQL的SQL优化_第4张图片

 load时,主键顺序插入性能高于乱序插入

主键优化

主键顺序插入的性能是要高于乱序插入的,主键又该如何设计
索引设计原则
  • 满足业务需求的情况下,尽量降低主键的长度。
  • 插入数据时,尽量选择顺序插入,选择使用AUTO_INCREMENT自增主键。尽量不要使用UUID做主键或者是其他自然主键,如身份证号。
  • 业务操作时,避免对主键的修改。

order by语句

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

无索引 

由于 age, phone 都没有索引,排序时,出现Using filesort, 排序性能较低。

explain select id,age,phone from tb_user order by age, phone ;

创建索引  

create index idx_user_age_phone_aa on tb_user(age,phone);

创建索引后,根据age, phone进行升序排序

 explain select age,phone from tb_user order by age,phone ;
Using index ,性能比较高

MYSQL的SQL优化_第5张图片

使用降序排序

创建索引后,根据age, phone进行降序排序,默认的排序是正序排序

explain select age,phone from tb_user order by age desc , phone desc ;

出现 Using index, 但是此时Extra中出现了 Backward index scan,这个代表反向扫描索引,因为在MySQL中我们创建的索引,默认索引的叶子节点是从小到大排序的,而此时我们查询排序时,是从大到小,所以,在扫描时,就是反向扫描,就会出现 Backward index scan 

MYSQL的SQL优化_第6张图片

不满足左前缀 

根据phoneage进行升序排序,phone在前,age在后。

explain select age,phone from tb_user order by phone , age;
排序时 , 也需要满足最左前缀法则 , 否则也会出现 filesort 。因为在创建索引的时候, age 是第一个
字段, phone 是第二个字段,所以排序时,也就该按照这个顺序来,否则就会出现 Usingfilesort。

 升降排序

 根据age, phone进行降序一个升序,一个降序

explain select age,phone from tb_user order by age asc , phone desc ;
因为创建索引时,如果未指定顺序,默认都是按照升序排序的,而查询时,一个升序,一个降序,此时就会出现Using filesort

为了解决上述的问题,我们可以创建一个索引,这个联合索引中 age 升序排序,phone 倒序排序。(如果创建失败,需要修改表的引擎为innodb,使用命令:alter table 表名 engine=innodb;

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

order by优化原则

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

group by语句

在没有索引的情况下,执行如下SQL,查询执行计划:  

explain select profession , count(*) from tb_user group by profession ;

Using temporary表示由于排序没有走索引 

在针对于 profession agestatus 创建一个联合索引。  

create index idx_user_pro_age_sta on tb_user(profession , age , status);

 再执行如下的分组查询SQL,查看执行计划

explain select profession , count(*) from tb_user group by profession ;

走索引的 

如果仅仅根据age分组,就会出现 Using temporary

MYSQL的SQL优化_第7张图片

原因是因为对于分组操作, 在联合索引中,也是符合最左前缀法则的。
group by优化
A. 在分组操作时,可以通过索引来提高效率。
B. 分组操作时,索引的使用也是满足最左前缀法则的。

limit语句

在数据量比较大时,如果进行 limit 分页查询,在查询时,越往后,分页查询效率越低。
当在进行分页查询时,如果执行 limit 2000000,10 ,此时需要 MySQL 排序前 2000010
录,仅仅返回 2000000 - 2000010 的记录,其他记录丢弃,查询排序的代价非常大 。

 

优化limit语句

一般分页查询时,通过创建 覆盖索引 能够比较好地提高性能,可以通过覆盖索引加子查
询形式进行优化
explain select * from tb_sku t , (select id from tb_sku order by id limit 2000000,10) a where t.id=a.id;

MYSQL的SQL优化_第8张图片

count语句

如果数据量很大,在执行count操作时,是非常耗时的。

  1. MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行 count(*) 的时候会直接返回这个数,效率很高; 但是如果是带条件的countMyISAM也慢。
  2. InnoDB 引擎就麻烦了,它执行 count(*) 的时候,需要把数据一行一行地从引擎里面读出来,然后累积计数。
如果说要大幅度提升 InnoDB 表的 count 效率,主要的优化思路:自己计数 ( 可以借助于 redis 这样的数据库进行, 但是如果是带条件的 count 又比较麻烦了 )
count() 是一个聚合函数,对于返回的结果集,一行行地判断,如果 count 函数的参数不是
NULL ,累计值就加 1 ,否则不加,最后返回累计值。

用法

count() 是一个聚合函数,对于返回的结果集,一行行地判断,如果 count 函数的参数不是
NULL ,累计值就加 1 ,否则不加,最后返回累计值。
用法: count * )、 count (主键)、 count (字段)、 count (数字)

 

count
含义
count(主 键)
InnoDB 引擎会遍历整张表,把每一行的 主键 id 值都取出来,返回给服务层。服务层拿到主键后,直接按行进行累加( 主键不可能为 null)
count(字 段)
没有 not null 约束 : InnoDB 引擎会遍历整张表把每一行的字段值都取出来,返回给服务层,服务层判断是否为null ,不为 null ,计数累加。有not null 约束: InnoDB 引擎会遍历整张表把每一行的字段值都取出来,返回给服务层,直接按行进行累加。
count( 数字)
InnoDB 引擎遍历整张表,但不取值。服务层对于返回的每一行,放一个数字 “1”进去,直接按行进行累加
count(*)
InnoDB 引擎并不会把全部字段取出来,而是专门做了优化,不取值,服务层直接按行进行累加。
InnoDB 引擎并不会把全部字段取出来,而是专门做了优化,不取值,服务层直接按行进行累加。

update语句

我们主要需要注意一下update语句执行时的注意事项。

update course set name = 'javaEE' where id = 1 ;

 当我们在执行删除的SQL语句时,会锁定id1这一行的数据,然后事务提交之后,行锁释放。

但是当我们在执行如下 SQL
update course set name = 'SpringBoot' where name = 'PHP' ; 
当我们开启多个事务,在执行上述的 SQL 时,我们发现行锁升级为了表锁。 导致该 update 语句的性能大大降低。
InnoDB 的行锁是针对索引加的锁,不是针对记录加的锁 , 并且该索引不能失效,否则会从行锁升级为表锁 。

你可能感兴趣的:(mysql面试题,mysql,sql,java)