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';
要导入的数据
连接数据库
set global local_infile = 1;开启本地导入数据
show global variables like 'local_infile';查看是否为on开启状态
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)
在load时,主键顺序插入性能高于乱序插入
主键优化
- 满足业务需求的情况下,尽量降低主键的长度。
- 插入数据时,尽量选择顺序插入,选择使用AUTO_INCREMENT自增主键。尽量不要使用UUID做主键或者是其他自然主键,如身份证号。
- 业务操作时,避免对主键的修改。
order by语句
- Using filesort : 通过表的索引或全表扫描,读取满足条件的数据行,然后在排序缓冲区sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫 FileSort 排序。
- 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 ;
使用降序排序
创建索引后,根据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。
不满足左前缀
根据phone,age进行升序排序,phone在前,age在后。
explain select age,phone from tb_user order by phone , age;
升降排序
根据age, phone进行降序一个升序,一个降序
explain select age,phone from tb_user order by age asc , phone desc ;

为了解决上述的问题,我们可以创建一个索引,这个联合索引中 age 升序排序,phone 倒序排序。(如果创建失败,需要修改表的引擎为innodb,使用命令:alter table 表名 engine=innodb;)
create index idx_user_age_phone_ad on tb_user(age asc ,phone desc);
order by优化原则
group by语句
在没有索引的情况下,执行如下SQL,查询执行计划:
explain select profession , count(*) from tb_user group by profession ;
Using temporary
表示由于排序没有走索引
在针对于 profession , age, status 创建一个联合索引。
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
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操作时,是非常耗时的。
- MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行 count(*) 的时候会直接返回这个数,效率很高; 但是如果是带条件的count,MyISAM也慢。
- InnoDB 引擎就麻烦了,它执行 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语句时,会锁定id为1这一行的数据,然后事务提交之后,行锁释放。
update course set name = 'SpringBoot' where name = 'PHP' ;
InnoDB 的行锁是针对索引加的锁,不是针对记录加的锁 , 并且该索引不能失效,否则会从行锁升级为表锁 。