Mysql 在5.6.3中,優化器更有效率地處理派生表(在from語句中的子查詢):
優化器推遲物化子查詢在from語句中的子查詢,知道子查詢的內容在查詢正真執行需要時,才開始物化。這一舉措提高了性能:
1:之前版本(5.6.3),from語句中的子查詢在explain select 查看執行計划語句執行時就會物化。它導致了部分查詢執行,但explain語句的目的是獲取執行計划信息,而不是執行查詢
該版本物化不會在explain中發生,所以explain執行計划結果的得到更快;
2:因為上面提及的,物化子查詢的推遲有可能不會發生。考慮一個from語句中的子查詢的結果和另一個表join(鏈接)查詢,如果優化器先處理另一張表A,然后發現A中沒有滿足條件的行返回,此時join不會再繼續執行,並且優化器會完全跳過物化子查詢這步驟;
考慮下面的explain語句,子查詢出現在form語句中;
EXPLAIN SELECT * FROM (SELECT * FROM t1) AS derived_t1;
優化器避免物化子查詢直到子查詢的結果在查詢真正執行需要時。在上面情況下,查詢並沒有執行,所有並沒有物化(子查詢);
即使查詢執行時,也會要求優化器去避免物化。考慮下面的查詢:
SELECT * FROM t1 JOIN (SELECT t2.f1 FROM t2) AS derived_t2 ON t1.f2=derived_t2.f1 WHERE t1.f1 > 0;
如果優化器先處理t1,並且where語句產生個空集,join結果必定是空集並且該子查詢沒必要去物化。
最壞的情況(派生表被物化),查詢執行會花費和之前版本之前的時間,在最好的情況下(派生表不會物化),查詢執行更快。
在派生表需要物化的情況下,優化器會通過為物化表添加索引來加速訪問物化表的結果,如果添加的索引允許ref方式訪問該物化表,會更好的減少在查詢執行時讀取的數據量。考慮下面的查詢:
SELECT * FROM t1 JOIN (SELECT DISTINCT f1 FROM t2) AS derived_t2 ON t1.f1=derived_t2.f1;
優化器在derived_t2派生表f1列構造一個索引,如果這樣允許ref方式來最小化執行計划的話費,添加索引,優化器對待物化的派生表和平常的帶index表一樣,添加index的花費比起查詢沒有Index的執行無不足道,如果ref方式比其他訪問方式花費更多,index不會添加,優化器不會做任何優化。
<======================分割線==================================>
From子查詢形式:
SELECT ... FROM (subquery) [AS] name ...
[AS] Name 語句是強制的(必須加上的)
, 因為From語句中每個表必須有一個名字. 子查詢中的每個select列必須有一個唯一的名字。
CREATE TABLE t1 (s1 INT, s2 CHAR(5), s3 FLOAT);
INSERT INTO t1 VALUES (1,'1',1.0); INSERT INTO t1 VALUES (2,'2',2.0); SELECT sb1,sb2,sb3 FROM (SELECT s1 AS sb1, s2 AS sb2, s3*2 AS sb3 FROM t1) AS sb WHERE sb1 > 1;
Result: 2, '2', 4.0
.
另一個例子:目的是想得到一組集合和的平均值。 下面的語句並不起作用:
SELECT AVG(SUM(column1)) FROM t1 GROUP BY column1;
正確格式:
SELECT AVG(sum_column1) FROM (SELECT SUM(column1) AS sum_column1 FROM t1 GROUP BY column1) AS t1;
From語句中的子查詢會返回一個標量一列,一行或者一個表。from語句中的子查詢不能是相關子查詢,除非有on 或者join關鍵字.
在Mysql5.6.3之前,from語句中的子查詢會在explain語句中執行(派生臨時表會被物化)。因為上層查詢需要得到所有表的信息在優化階段。在某些情況下用explain select語句會修改表數據,如果外部查詢訪問所有表,並且內部查詢調用一個修改表數據行的存儲方法,見下:
mysql> create table t1(c1 int); Query OK, 0 rows affected (0.39 sec) mysql> create table t2(c1 int); Query OK, 0 rows affected (0.26 sec)
現在創建一個修改t2表的存儲方法;
mysql> delimiter // mysql> create function f1(p1 int) returns int -> begin -> insert into t2 values(p1); -> return p1; -> end // Query OK, 0 rows affected (0.00 sec) mysql> delimiter ;
直接引用該存儲方法在一個explain select 語句中不會對t2有任何作用;
mysql> select * from t2; Empty set (0.00 sec) mysql> explain select f1(5); +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used | +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 1 row in set (0.00 sec)
這是因為select語句沒用引用任何表, 可以在table和extra列中輸出看到:
mysql> explain select now() as a1,(select f1(5)) as a2; +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used | +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 1 row in set, 1 warning (0.00 sec) mysql> show warnings; +-------+------+------------------------------------------+ | Level | Code | Message | +-------+------+------------------------------------------+ | Note | 1249 | Select 2 was reduced during optimization | +-------+------+------------------------------------------+ 1 row in set (0.00 sec)
然而, 當外部select引用任何表時,優化器會執行子查詢:
mysql> explain select * from t1 as a1,(select f1(5)) as a2; +----+-------------+------------+--------+---------------+------+---------+------+------+----------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+--------+---------------+------+---------+------+------+----------------+ | 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | NULL | | 1 | PRIMARY | a1 | ALL | NULL | NULL | NULL | NULL | 1 | NULL | | 2 | DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used | +----+-------------+------------+--------+---------------+------+---------+------+------+----------------+ 3 rows in set (0.02 sec) mysql> select * from t2; +------+ | c1 | +------+ | 5 | +------+ 1 row in set (0.00 sec)
這也意味着一個explain select語句(如上)也會需要一段時間來執行.