1. 大批量插入数据
1. 按主键顺序插入
- InnoDB类型的表是按照主键的顺序保存的(聚簇索引B+树)。
- 将导入的数据按照主键的顺序排列,可以有效的提高导入数据的效率
2. 导入数据时关闭唯一性校验
SET UNIQUE_CHECKS=0;
- 导入数据前关闭唯一性校验
- 导入完成后再开启唯一性校验
3. 导入数据前设置为手动提交事务
SET AUTOCOMMIT=0;
- 导入数据前关闭自动提交事务
- 导入数据后再打开自动提交事务
2. 优化insert语句
1. 对某张表插入多条数据应合并为一条语句
insert into tb_test values(1,'Tom');
insert into tb_test values(2,'Cat');
insert into tb_test values(3,'Jerry');
// 优化后
insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');
2. 插入数据有序插入
3. 优化order by语句
// 建表语句
CREATE TABLE `emp` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`age` int(3) NOT NULL,
`salary` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
insert into `emp` (`id`, `name`, `age`, `salary`) values('1','Tom','25','2300');
insert into `emp` (`id`, `name`, `age`, `salary`) values('2','Jerry','30','3500');
insert into `emp` (`id`, `name`, `age`, `salary`) values('3','Luci','25','2800');
insert into `emp` (`id`, `name`, `age`, `salary`) values('4','Jay','36','3500');
insert into `emp` (`id`, `name`, `age`, `salary`) values('5','Tom2','21','2200');
insert into `emp` (`id`, `name`, `age`, `salary`) values('6','Jerry2','31','3300');
insert into `emp` (`id`, `name`, `age`, `salary`) values('7','Luci2','26','2700');
insert into `emp` (`id`, `name`, `age`, `salary`) values('8','Jay2','33','3500');
insert into `emp` (`id`, `name`, `age`, `salary`) values('9','Tom3','23','2400');
insert into `emp` (`id`, `name`, `age`, `salary`)
values('10','Jerry3','32','3100');
insert into `emp` (`id`, `name`, `age`, `salary`) values('11','Luci3','26','2900');
insert into `emp` (`id`, `name`, `age`, `salary`) values('12','Jay3','37','4500');
create index idx_emp_age_salary on emp(age,salary);
1. filesort排序
explain select * from emp order by age;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 12 | 100.00 | Using filesort |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
1 row in set, 1 warning (0.01 sec)
- 全表扫描,然后对返回的数据进行排序,集filesort排序。
- 所有不是通过索引直接返回排序结果的排序都加Filesort排序
- 未使用到索引,因为需要全表扫描数据,再对age排序
2. 通过有序索引顺序扫描直接返回有序数据
explain select id from emp order by age asc;
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | index | NULL | idx_emp_age_salary | 9 | NULL | 12 | 100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
explain select id,age from emp order by age desc;
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | index | NULL | idx_emp_age_salary | 9 | NULL | 12 | 100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
explain select id,age,salary from emp order by age desc;
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | index | NULL | idx_emp_age_salary | 9 | NULL | 12 | 100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
- 满足复合索引(age,salary)的最左前缀原则,而且不需要回表操作
3. 多字段排序
explain select id,age,salary from emp order by age asc,salary asc;
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | index | NULL | idx_emp_age_salary | 9 | NULL | 12 | 100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
explain select id,age,salary from emp order by age desc,salary desc;
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | index | NULL | idx_emp_age_salary | 9 | NULL | 12 | 100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
- 多字段排序中同升序同降序可以走索引排序
explain select id,age,salary from emp order by age desc,salary asc;
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-----------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-----------------------------+
| 1 | SIMPLE | emp | NULL | index | NULL | idx_emp_age_salary | 9 | NULL | 12 | 100.00 | Using index; Using filesort |
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-----------------------------+
1 row in set, 1 warning (0.00 sec)
explain select id,age,salary from emp order by salary asc,age asc;
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-----------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-----------------------------+
| 1 | SIMPLE | emp | NULL | index | NULL | idx_emp_age_salary | 9 | NULL | 12 | 100.00 | Using index; Using filesort |
+----+-------------+-------+------------+-------+---------------+--------------------+---------+------+------+----------+-----------------------------+
1 row in set, 1 warning (0.00 sec)
- 多字段排序中不满足同升序同降序或者不满足最左前缀原则,则不走索引排序。
- 但是因为查找的三个字段都在索引上,所以还是用到了索引。
4. 优化group by语句
- group by实际上也会进行排序操作
- 与order by相比,group by主要多了排序之后的分组操作。
- 所以group by过程中一样可以使用索引甚至复合索引
- 但是还是一样要满足索引的最左前缀原则
1. 删除索引后会发现进行了fileSort
drop index idx_emp_age_salary on emp;
explain select age,count(*) from emp group by age;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 12 | 100.00 | Using temporary; Using filesort |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
1 row in set, 1 warning (0.00 sec)
2. 创建索引后发现走索引排序了。
create index idx_emp_age_salary on emp(age,salary);
explain select age,count(*) from emp group by age;
+----+-------------+-------+------------+-------+--------------------+--------------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+--------------------+--------------------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | index | idx_emp_age_salary | idx_emp_age_salary | 9 | NULL | 12 | 100.00 | Using index |
+----+-------------+-------+------------+-------+--------------------+--------------------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
5. 优化嵌套查询
1. 将有些子查询优化为连接查询
- 因为连接查询不需要再内存中创建一个临时表,所以效率会高一些
explain select * from t_user where id in (select user_id from user_role);
+----+--------------+-------------+------------+--------+---------------+---------------+---------+-----------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+-------------+------------+--------+---------------+---------------+---------+-----------------+------+----------+-------------+
| 1 | SIMPLE | t_user | NULL | ALL | PRIMARY | NULL | NULL | NULL | 6 | 100.00 | Using where |
| 1 | SIMPLE | <subquery2> | NULL | eq_ref | <auto_key> | <auto_key> | 99 | test1.t_user.id | 1 | 100.00 | NULL |
| 2 | MATERIALIZED | user_role | NULL | index | fk_ur_user_id | fk_ur_user_id | 99 | NULL | 6 | 100.00 | Using index |
+----+--------------+-------------+------------+--------+---------------+---------------+---------+-----------------+------+----------+-------------+
3 rows in set, 1 warning (0.00 sec)
优化后
explain select * from t_user u,user_role ur where u.id=ur.user_id;
+----+-------------+-------+------------+--------+---------------+---------+---------+------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+---------------+---------+---------+------------------+------+----------+-------------+
| 1 | SIMPLE | ur | NULL | ALL | fk_ur_user_id | NULL | NULL | NULL | 6 | 100.00 | Using where |
| 1 | SIMPLE | u | NULL | eq_ref | PRIMARY | PRIMARY | 98 | test1.ur.user_id | 1 | 100.00 | NULL |
+----+-------------+-------+------------+--------+---------------+---------+---------+------------------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
6. 优化or条件
- 建议将union替换or条件
7. 优化分页查询
- limit 2000000,10 这样的情况需要先排序前2000010条记录,仅仅返回2000000-2000010的记录
- 所以优化的思路是最好再所以上确定第2000000条的记录,然后返回之后的十条记录。
- 即思想还是建立有序索引。先查索引,再回表(对于复合索引甚至不需要回表)
8. 使用sql提示
1. 查询时推荐mysql使用某个索引
explain select * from tb_seller use index(idx_seller_name) where name='小米科技';
2. 查询时忽略某个索引
explain select * from tb_seller ignore index(idx_seller_name) where name = '小米科技';
3. 查询时强制使用某个索引
explain select * from tb_seller force index(idx_seller_name) where name='小米科技';