MYSQL优化派生表(子查询)在From语句中的

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语句(如上)也会需要一段时间来执行.

时间: 2024-09-28 18:25:45

MYSQL优化派生表(子查询)在From语句中的的相关文章

mysql优化---in型子查询,exists子查询,from 型子查询

in型子查询引出的陷阱:(扫更少的行,不要临时表,不要文件排序就快) 题: 在ecshop商城表中,查询6号栏目的商品, (注,6号是一个大栏目) 最直观的: mysql> select goods_id,cat_id,goods_name from goods where cat_id in (select cat_id from category where parent_id=6); 误区: 给我们的感觉是, 先查到内层的6号栏目的子栏目,如7,8,9,11 然后外层, cat_id in

MySQL 表子查询

MySQL 表子查询 表子查询是指子查询返回的结果集是 N 行 N 列的一个表数据. MySQL 表子查询实例 下面是用于例子的两张原始数据表: article 表: aid title content uid 1 文章1 文章1正文内容... 1 2 文章2 文章2正文内容... 1 3 文章3 文章3正文内容... 2 4 文章4 文章4正文内容... 3 blog 表: bid title content uid 1 日志1 日志1正文内容... 1 2 文章2 文章2正文内容... 1

mysql优化(三)–explain分析sql语句执行效率

mysql优化(三)–explain分析sql语句执行效率 mushu 发布于 11个月前 (06-04) 分类:Mysql 阅读(651) 评论(0) Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看SQL语句的执行效 果,可以帮助选择更好的索引和优化查询语句,写出更好的优化语句. Explain语法:explain select … from … [where …] 例如:explain select * from

sql子查询 嵌套SELECT语句

嵌套SELECT语句也叫子查询,一个 SELECT 语句的查询结果能够作为另一个语句的输入值.子查询不但能够出现在Where子句中,也能够出现在from子句中,作为一个临时表使用,也能够出现在select list中,作为一个字段值来返回. 1.单行子查询 :单行子查询是指子查询的返回结果只有一行数据.当主查询语句的条件语句中引用子查询结果时可用单行比较符号(=, >, <, >=, <=, <>)来进行比较. 例:select ename,deptno,salfrom

mysql——多表——子查询——示例

子查询: 子查询是将一个查询语句嵌套在另外一个查询语句中,内层查询语句的查询结果,可以作为外来层查询语句提供查询条件. 因此在特定条件下,一个查询语句的条件,需要另外一个查询语句来获取. 前期准备表: create table employee ( num int(50), d_id int(50), name varchar(50), age int(50), sex varchar(50), homeadd varchar(50) ); insert into employee values

优化系列 | DELETE子查询改写优化

0.导读 有个采用子查询的DELETE执行得非常慢,改写成SELECT后执行却很快,最后把这个子查询DELETE改写成JOIN优化过程 1.问题描述 朋友遇到一个怪事,一个用子查询的DELETE,执行效率非常低.把DELETE改成SELECT后执行起来却很快,百思不得其解. 下面就是这个用了子查询的DELETE了: [[email protected]]mydb > EXPLAIN delete from trade_info where id in ( select id from ( sel

浅析TPCH对查询Q4的优化-正确改写子查询与强制使用索引优化

1.源查询语句执行计划 EXPLAIN EXTENDED SELECT sql_no_cache O_ORDERPRIORITY, COUNT(*) AS ORDER_COUNT FROM ORDERS WHERE O_ORDERDATE >= DATE '1993-07-01' AND O_ORDERDATE < DATE '1993-07-01' + INTERVAL '3' MONTH AND EXISTS ( SELECT * FROM LINEITEM WHERE L_ORDERKE

MySQL优化篇之慢查询

1.什么是MySQL的慢查询? mysql中最影响速度的就是那些查询非常慢的语句,这些慢的语句,可能是写的不够合理或者是大数据下多表的联合查询等等,所以我们要找出这些语句,分析原因,加以优化. 2.查看和配置MYSQL慢查询相关信息 第一,慢查询,这个慢,时间上是怎么定义的?多久才算慢呢? MYSQL有2种类型的变量,一个是服务器变量(show variables),一个是状态变量(show status).这2种变量都分global/session. 从上图可以看出,10秒以内执行完毕的SQL

MySQL(三) 数据库表的查询操作【重要】

序言 1.MySQL表操作(创建表,查询表结构,更改表字段等), 2.MySQL的数据类型(CHAR.VARCHAR.BLOB,等), 本节比较重要,对数据表数据进行查询操作,其中可能大家不熟悉的就对于INNER JOIN(内连接).LEFT JOIN(左连接).RIGHT JOIN(右连接)等一些复杂查询. 通过本节的学习,可以让你知道这些基本的复杂查询是怎么实现的,但是建议还是需要多动手去敲,虽然理解了什么是内连接等,但是从理解到学会,是完全不一样的感觉. --WH 一.单表查询 1.1.查