在實現業務邏輯的時候,有些複雜一點邏輯會用數據庫子查詢去實現,可是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數據庫運維與架構設計)性能