在实现业务逻辑的时候,有些复杂一点逻辑会用数据库子查询去实现,可是sql用子查询会带来性能问题,下面就一个例子来讲明,怎么优化子查询,来提高查询速度mysql
mysql> desc update t_student_info a
-> set a.exstudentid='test01'
-> where a.studentID in
-> (select studentID from (select studentID from t_student_info where stdTYPE='8' and state=2 limit 10000,100) b);
+----+--------------------+----------------+------------+----------------+---------------+-------------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+----------------+------------+----------------+---------------+-------------+---------+------+--------+----------+-------------+
| 1 | UPDATE | a | NULL | index | NULL | PRIMARY | 24 | NULL | 221058 | 100.00 | Using where |
| 2 | DEPENDENT SUBQUERY | <derived3> | NULL | index_subquery | <auto_key0> | <auto_key0> | 24 | func | 221 | 100.00 | Using index |
| 3 | DERIVED | t_student_info | NULL | ALL | NULL | NULL | NULL | NULL | 221058 | 1.00 | Using where |
+----+--------------------+----------------+------------+----------------+---------------+-------------+---------+------+--------+----------+-------------+
3 rows in set (0.00 sec)复制代码
能够看到这个Update语句的执行计划,用的是DEPENDENT SUBQUERY,这样就须要循环的去执行这个只查询,效率会慢,能不能把这个只查询改一下,改为join查询呢,下面就是优化以后的sql写法sql
update t_student_info a set a.exstudentid='test01' where a.studentID in (select studentID from (select studentID from t_student_info where stdTYPE='8' and state=2 limit 10000,100) b)
mysql> desc update t_student_info a
-> inner join
-> (select studentID from t_student_info where stdTYPE='8' and state=2 limit 10000,100) b
-> on a.studentID=b.studentID
-> set a.exstudentid='test01';
+----+-------------+----------------+------------+--------+---------------+---------+---------+-------------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------------+------------+--------+---------------+---------+---------+-------------+--------+----------+-------------+
| 1 | PRIMARY | <derived2> | NULL | ALL | NULL | NULL | NULL | NULL | 2210 | 100.00 | NULL |
| 1 | UPDATE | a | NULL | eq_ref | PRIMARY | PRIMARY | 24 | b.studentID | 1 | 100.00 | NULL |
| 2 | DERIVED | t_student_info | NULL | ALL | NULL | NULL | NULL | NULL | 221058 | 1.00 | Using where |
+----+-------------+----------------+------------+--------+---------------+---------+---------+-------------+--------+----------+-------------+
3 rows in set (0.00 sec)复制代码
能够从执行计划中看到执行计划已经从DEPENDENT SUBQUERY变成了DERIVED,以驱动表去关联查询了,下面来看看实际执行效果数据库
mysql> update t_student_info a set a.exstudentid='test01' where a.studentID in (select studentID from (select studentID from t_student_info where stdTYPE='8' and state=2 limit 10000,100) b);
Query OK, 0 rows affected (0.37 sec)
Rows matched: 100 Changed: 0 Warnings: 0
mysql> update t_student_info a set a.exstudentid='test01' where a.studentID in (select studentID from (select studentID from t_student_info where stdTYPE='8' and state=2 limit 10000,100) b);
Query OK, 0 rows affected (0.39 sec)
Rows matched: 100 Changed: 0 Warnings: 0
mysql> update t_student_info a inner join (select studentID from t_student_info where stdTYPE='8' and state=2 limit 10000,100) b on a.studentID=b.studentID set a.exstudentid='test01';
Query OK, 0 rows affected (0.07 sec)
Rows matched: 100 Changed: 0 Warnings: 0
mysql> update t_student_info a inner join (select studentID from t_student_info where stdTYPE='8' and state=2 limit 10000,100) b on a.studentID=b.studentID set a.exstudentid='test01';
Query OK, 0 rows affected (0.07 sec)
Rows matched: 100 Changed: 0 Warnings: 0复制代码
为了排除由于物理读致使的干扰,没条sql都连续执行2遍,从执行结果能够看到,使用子查询的sql平均执行时间在370毫秒,而用inner join的sql平均执行时间在70毫秒,效率提高了5倍多,优化效果仍是很明显的,小伙伴可能会以为,才有5倍提高,其实优化以后的语句耗费时间的在limit 10000,100这里,若是改外limit 1,100你们再来看看对比效果架构
mysql> update t_student_info a inner join (select studentID from t_student_info where stdTYPE='8' and state=2 limit 1,100) b on a.studentID=b.studentID set a.exstudentid='test01';
Query OK, 0 rows affected (0.00 sec)
Rows matched: 100 Changed: 0 Warnings: 0
mysql> update t_student_info a inner join (select studentID from t_student_info where stdTYPE='8' and state=2 limit 1,100) b on a.studentID=b.studentID set a.exstudentid='test01';
Query OK, 0 rows affected (0.00 sec)
Rows matched: 100 Changed: 0 Warnings: 0
mysql> update t_student_info a set a.exstudentid='test01' where a.studentID in (select studentID from (select studentID from t_student_info where stdTYPE='8' and state=2 limit 1,100) b);
Query OK, 0 rows affected (0.31 sec)
Rows matched: 100 Changed: 0 Warnings: 0
mysql> update t_student_info a set a.exstudentid='test01' where a.studentID in (select studentID from (select studentID from t_student_info where stdTYPE='8' and state=2 limit 1,100) b);
Query OK, 0 rows affected (0.31 sec)
Rows matched: 100 Changed: 0 Warnings: 0复制代码
inner join的执行时间已是几毫秒了,而子查询仍是在310毫秒,这效果就分明显,提高了100多倍,这种方法优化,不只适合in,仍是适合exists的优化运维
喜欢的同窗能够关注个人公众号(db_arch)(Mysql数据库运维与架构设计)性能