一、MySQL子查询的位置  当一个查询是另一个查询的子部分是,称之为子查询(查询语句中嵌套含有查询语句)。子查询也是使用频率比较高的一种查询类型。因此,优化子查询,对于整个系统的性能也有直接的影响。1 、子查询出现在目标列位置 create table t1 (k1 int primary key, c1 int);
create table t2 (k2 int primary key, c2 int);
insert into t2 values (1, 10), (2, 2), (3,30);a 、 此时若我们执行如下SQL语句的结果为:mysql> select t1.c1, (select t2.c2 from t2) from t1, t2;
Empty set (0.00sec)b 、 然后,我们往t1表中插入一些数据:mysql> insert into t1 values (1, 1), (2, 2), (3, 3);
Query OK, 3 rows affected (0.00 sec)c 、 此时,我们再次执行a中的查询,我们可以看到执行的结果mysql>select t1.c1, (select t2.c2 from t2) from t1, t2;
ERROR 1242(21000): Subquery returns more than 1 rowd 、 此时我们清空t2表,然后再执行a中所做的查询。mysql>delete from t2;
QueryOK, 3 rows affected (0.00 sec)
 
mysql> select t1.c1, (select t2.c2 from t2) from t1, t2;
Empty set (0.00 sec)e 、 我们进一步实验。现在我们把刚刚从t2表中删除的数据在插入到t2表:mysql>insert into t2 values (1, 10), (2, 2), (3, 30);
Query OK,3 rows affected (0.00 sec)mysql> select t1.c1, (select t2.c2 from t2 where k2=1) from t1, t2;
+------+-----------------------------------+
| c1   | (select t2.c2 from t2 where k2=1) |
+------+-----------------------------------+
|  1 |                10 |
|  2 |                10 |
|  3 |                10 |
|  1 |                10 |
|  2 |                10 |
|  3 |                10 |
|  1 |                10 |
|  2 |                10 |
|  3 |                10 |
+------+-----------------------------------+mysql> select t1.c1, (selectt2.c2 from t2 where c2 > 1) from t1, t2;
ERROR 1242 (21000): Subqueryreturns more than 1 row2 、子查询出现在 FROM 字句的位置 mysql> select * from t1, (select *from t2 where t1.k1 = t2.k2);
ERROR 1248 (42000): Every derived table musthave its own aliasmysql> select * from t1, (select * from t2) as a_t2;
+----+------+----+------+
| k1 | c1   | k2 | c2   |
+----+------+----+------+
|  1 |  1 |  1 |   10 |
|  2 |  2 |  1 |   10 |
|  3 |  3 |  1 |   10 |
|  1 |  1 |  2 |  2 |
|  2 |  2 |  2 |  2 |
|  3 |  3 |  2 |  2 |
|  1 |  1 |  3 |   30 |
|  2 |  2 |  3 |   30 |
|  3 |  3 |  3 |   30 |
+----+------+----+------+
9 rows in set (0.00 sec)3 、子查询出现在 WHERE 子句当中 4 、 JOIN/ON 字句位置 1 、从查询对象间的关系上来区分 mysql> select * from t1 where c1 = ANY (select c2 from t2 where t2.c2 = t1.c1);
+----+------+
| k1 | c1   |
+----+------+
|  2 |  2 |
+----+------+
1 row in set (0.12 sec)mysql> select * from t1 where c1 = ANY(select c2 from t2 where t2.c2=10);
Empty set (0.02 sec)2 、从特定的谓词来区分 1 、子查询合并 mysql> select * from t1 where k1 < 10 and (
  -> exists(select k2 from t2 where t2.k2 < 5 and t2.c2 = 1) or
  -> exists(select k2 from t2 where t2.k2 < 5 and t2.c2 = 2)
  -> );
+----+------+
| k1 | c1   |
+----+------+
|  1 |  1 |
|  2 |  2 |
|  3 |  3 |
+----+------+
3 rows in set (0.12 sec)mysql> explain extended select * from t1 where k1 < 10 and (
  -> exists(select k2 from t2 where t2.k2 < 5 and t2.c2 = 1) or
  -> exists(select k2 from t2 where t2.k2 < 5 and t2.c2 = 2)
  -> );
+----+-------------+-------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows | filtered | Extra     |
+----+-------------+-------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | PRIMARY   | t1  | range | PRIMARY     | PRIMARY | 4     | NULL |  3 |   100.00 | Using where |
|  3 | SUBQUERY  | t2  | range | PRIMARY     | PRIMARY | 4     | NULL |  3 |   100.00 | Using where |
|  2 | SUBQUERY  | t2  | range | PRIMARY     | PRIMARY | 4     | NULL |  3 |   100.00 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+------+----------+-------------+
3 rows in set, 1 warning (0.00 sec)mysql> select * from t1 where k1 < 10 and (
  -> exists(select k2 from t2 where t2.k2 < 5 and (t2.c2 = 1 or t2.c2 = 2))
  -> );
+----+------+
| k1 | c1   |
+----+------+
|  1 |  1 |
|  2 |  2 |
|  3 |  3 |
+----+------+
3 rows in set (0.00 sec)mysql> explain extended select * from t1 where k1 < 10 and (
  -> exists(select k2 from t2 where t2.k2 < 5 and (t2.c2 = 1 or t2.c2 = 2))
  -> );
+----+-------------+-------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows | filtered | Extra     |
+----+-------------+-------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | PRIMARY   | t1  | range | PRIMARY     | PRIMARY | 4     | NULL |  3 |   100.00 | Using where |
|  2 | SUBQUERY  | t2  | range | PRIMARY     | PRIMARY | 4     | NULL |  3 |   100.00 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)2 、子查询展开 mysql> explain select * from t1, (select * from t2 where t2.k2 > 10) v_t2 where t1.k1 < 10 and v_t2.k2 < 20;
+----+-------------+------------+-------+---------------+---------+---------+------+------+----------------------------------------------------+
| id | select_type | table    | type  | possible_keys | key   | key_len | ref  | rows | Extra                        |
+----+-------------+------------+-------+---------------+---------+---------+------+------+----------------------------------------------------+
|  1 | PRIMARY   | t1     | range | PRIMARY     | PRIMARY | 4     | NULL |  3 | Using where                    |
|  1 | PRIMARY   | <derived2> | ALL   | NULL      | NULL  | NULL  | NULL |  2 | Using where; Using join buffer (Block Nested Loop) |
|  2 | DERIVED   | t2     | range | PRIMARY     | PRIMARY | 4     | NULL |  1 | Using where                    |
+----+-------------+------------+-------+---------------+---------+---------+------+------+----------------------------------------------------+
3 rows in set (0.00 sec)mysql> explain extended select * from t1 where t1.a1 < 100 and t1.a1 in(select a2 from t2 where t2.a2 > 10); 
+----+-------------+-------+--------+---------------+---------+---------+--------------+------+----------+-------------+
| id | select_type | table | type   | possible_keys | key   | key_len | ref      | rows | filtered | Extra     |
+----+-------------+-------+--------+---------------+---------+---------+--------------+------+----------+-------------+
|  1 | SIMPLE    | t1  | range  | PRIMARY     | PRIMARY | 4     | NULL     |   88 |   100.00 | Using where |
|  1 | SIMPLE    | t2  | eq_ref | PRIMARY     | PRIMARY | 4     | testdb.t1.a1 |  1 |   100.00 | Using index |
+----+-------------+-------+--------+---------------+---------+---------+--------------+------+----------+-------------+
2 rows in set, 1 warning (0.32 sec)1 、 MySQL 支持什么类型的子查询                                                ( 1 )简单的 select 查询中的子查询。 为了对这些查询做出一些测试,我们来新建一些表,并且批量插入一些数据。 下面这段Python代码实现了创建三张表,并且每张表里插入 15000 条数据: import MySQLdb as mdb 
import random
host = '10.12.128.12'
name = 'root'
password = '123456'
db = 'testdb'
try:
conn = mdb.connect(host, name, password, db)
cur = conn.cursor()
for i in range(1, 4):
sql = 'create table t%d(a%d int primary key auto_increment, b%d int)' % (i, i, i)
cur.execute(sql)
for j in range(1, 15000):
value = random.randint(1, 15000)
s = 'insert into t%d(b%d) values(%d)' % (i, i, value)
cur.execute(s);
cur.close()
finally:
if conn:
conn.close()2 、 MySQL 不支持对什么样的子查询进行优化 带有 UNOIN 操作的查询 带有 GROUPBY 、 HAVING 、聚集函数的查询 使用 ORDERBY 中带有 LIMIT 的查询 内表外表的连接数超过 MySQL 最大表的连接数 下面我们就来简单验证一下第一个: 带有 GROUPBY 、 HAVING 、聚集函数的查询 mysql> EXPLAIN EXTENDED SELECT * FROM t1 WHERE t1.a1>(SELECT MIN(t2.a2) FROM t2);
+----+-------------+-------+-------+---------------+---------+---------+------+------+----------+------------------------------+
| id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows | filtered | Extra            |
+----+-------------+-------+-------+---------------+---------+---------+------+------+----------+------------------------------+
|  1 | PRIMARY   | t1  | range | PRIMARY     | PRIMARY | 4     | NULL | 7534 |   100.00 | Using where          |
|  2 | SUBQUERY  | NULL  | NULL  | NULL      | NULL  | NULL  | NULL | NULL |   NULL | Select tables optimized away |
+----+-------------+-------+-------+---------------+---------+---------+------+------+----------+------------------------------+
2 rows in set, 1 warning (0.11 sec)2 、MySQL 查询优化实例mysql> explain  extended select * from t1 where t1.a1 NOT IN (select a2 from t2 where t2.a2 > 10);
+----+-------------+-------+-------+---------------+---------+---------+------+-------+----------+--------------------------+
| id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows  | filtered | Extra          |
+----+-------------+-------+-------+---------------+---------+---------+------+-------+----------+--------------------------+
|  1 | PRIMARY   | t1  | ALL   | NULL      | NULL  | NULL  | NULL | 15068 |   100.00 | Using where        |
|  2 | SUBQUERY  | t2  | range | PRIMARY     | PRIMARY | 4     | NULL |  7534 |   100.00 | Using where; Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+-------+----------+--------------------------+
2 rows in set, 1 warning (0.00 sec)mysql> show warnings\G
*************************** 1. row ***************************
  Level: Note
   Code: 1003
Message: /* select#1 */ select `testdb`.`t1`.`a1` AS `a1`,`testdb`.`t1`.`b1` AS `b1` from `testdb`.`t1` where (not(<in_optimizer>(`testdb`.`t1`.`a1`,`testdb`.`t1`.`a1` in ( <materialize> (/* select#2 */ select `testdb`.`t2`.`a2` from `testdb`.`t2` where (`testdb`.`t2`.`a2` > 10) ), <primary_index_lookup>(`testdb`.`t1`.`a1` in <temporary table> on <auto_key> where ((`testdb`.`t1`.`a1` = `materialized-subquery`.`a2`)))))))
1 row in set (0.00 sec)mysql> explain extended select * from t1 where t1.a1 > ALL(select a2 from t2 where t2.a2 > 10);
+----+-------------+-------+------+---------------+------+---------+------+-------+----------+------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | filtered | Extra            |
+----+-------------+-------+------+---------------+------+---------+------+-------+----------+------------------------------+
|  1 | PRIMARY   | t1  | ALL  | NULL      | NULL | NULL  | NULL | 15068 |   100.00 | Using where          |
|  2 | SUBQUERY  | NULL  | NULL | NULL      | NULL | NULL  | NULL |  NULL |   NULL | Select tables optimized away |
+----+-------------+-------+------+---------------+------+---------+------+-------+----------+------------------------------+
2 rows in set, 1 warning (0.03 sec)mysql> show warnings\G
*************************** 1. row ***************************
  Level: Note
   Code: 1003
Message: /* select#1 */ select `testdb`.`t1`.`a1` AS `a1`,`testdb`.`t1`.`b1` AS `b1` from `testdb`.`t1` where <not>((`testdb`.`t1`.`a1` <= (/* select#2 */ select max(`testdb`.`t2`.`a2`) from `testdb`.`t2` where (`testdb`.`t2`.`a2` > 10))))
1 row in set (0.00 sec)mysql> explain extended select * from t1 where t1.a1 > SOME (select a2 from t2 where t2.a2 > 10);
+----+-------------+-------+------+---------------+------+---------+------+-------+----------+------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | filtered | Extra            |
+----+-------------+-------+------+---------------+------+---------+------+-------+----------+------------------------------+
|  1 | PRIMARY   | t1  | ALL  | NULL      | NULL | NULL  | NULL | 15068 |   100.00 | Using where          |
|  2 | SUBQUERY  | NULL  | NULL | NULL      | NULL | NULL  | NULL |  NULL |   NULL | Select tables optimized away |
+----+-------------+-------+------+---------------+------+---------+------+-------+----------+------------------------------+
2 rows in set, 1 warning (0.00 sec)mysql> show warnings\G
*************************** 1. row ***************************
  Level: Note
   Code: 1003
Message: /* select#1 */ select `testdb`.`t1`.`a1` AS `a1`,`testdb`.`t1`.`b1` AS `b1` from `testdb`.`t1` where <nop>((`testdb`.`t1`.`a1` > (/* select#2 */ select min(`testdb`.`t2`.`a2`) from `testdb`.`t2` where (`testdb`.`t2`.`a2` > 10))))
1 row in set (0.00 sec)  select_type:表示select类型,常见的取值有SIMPLE(不使用表连接或子查询)、PRIMARY(主查询,即外层的查询)、UNION(UNION中的或者后面的查询语句)、SUBQUERY(子查询中的第一个select)等。   table:输出结果集的表。   type:表示表的连接类型,性能由好到差的连接类型为system(表中仅有一行,即常量表)、const(单表中最多有一个匹配行,例如PRIMARY KEY或者UNIQUE INDEX)、eq_ref(对于前面的每一行,在此表中只查询一条记录,简单来说,就是多表连接中使用PRIMARYKEY或者UNIQUE INDEX)、ref(与eq_ref类似,区别在于不使用PRIMARYKEY或者UNIQUE INDEX,而是使用普通的索引)、ref_of_null(与ref类似,区别在于条件中包含对NULL的查询)、index_merge(索引合并化)、unique_subquery(in的后面是一个查询主键字段的子查询)、index_subquery(与unique_subquery类似,区别在于in的后面是查询非唯一索引字段的子查询)、range(单表中的范围查询)、index(对于前面的每一行都通过查询索引来得到数据)、all(对于前面的每一行的都通过全表扫描来获得数据)。   possible_keys:表示查询时,可能使用到的索引。   key:表示实际使用的索引   key_len:索引字段的长度   rows:扫描行的数量   extra:执行情况的说明和描述。