Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 子查询表中的查询是否得到优化?_Mysql_Sql_Postgresql_Sql Execution Plan - Fatal编程技术网

Mysql 子查询表中的查询是否得到优化?

Mysql 子查询表中的查询是否得到优化?,mysql,sql,postgresql,sql-execution-plan,Mysql,Sql,Postgresql,Sql Execution Plan,关于查询优化,我想知道下面这样的语句是否得到了优化: select * from ( select * from table1 t1 join table2 t2 using (entity_id) order by t2.sort_order, t1.name ) as foo -- main query of object where foo.name = ?; -- inserted 假设查询由依赖项对象处理,但只是(正确地)允许一个WHERE条件。我

关于查询优化,我想知道下面这样的语句是否得到了优化:

select *
from (
    select *
    from table1 t1
    join table2 t2 using (entity_id)
    order by t2.sort_order, t1.name
)   as foo -- main query of object
where foo.name = ?; -- inserted
假设查询由依赖项对象处理,但只是(正确地)允许一个WHERE条件。我认为至少没有太多的数据被拉入到您最喜欢的语言中,但如果这是一个充分的优化,我会重新考虑,也许数据库仍然需要一些时间来完成查询


或者最好将该查询取出并编写一个单独的查询方法,其中包含where,也可能有一个
LIMIT 1
子句?

MySQL中,否

外部查询中的谓词不会被“下推”到内联视图查询中

首先处理内联视图中的查询,独立于外部查询。(MySQL将优化该视图查询,就像您单独提交该查询一样。)

MySQL处理此查询的方式:首先运行内联视图查询,结果被具体化为“派生表”。也就是说,该查询的结果集在某些情况下作为临时表存储在内存中(如果它足够小,并且不包含内存引擎不支持的任何列。否则,它将使用MyISAM存储引擎作为MyISAM表旋转到磁盘

填充派生表后,外部查询将运行


(请注意,派生表上没有任何索引。这在5.6之前的MySQL版本中是正确的;我认为5.6中有一些改进,MySQL将实际创建索引

澄清:派生表上的索引:从MySQL 5.6.3开始,“在查询执行期间,优化器可能会向派生表添加索引,以加快从派生表检索行的速度。”参考:

此外,我认为MySQL不会从内联视图中“优化”出任何不需要的列。如果内联视图查询是
SELECT*
,那么所有列都将在派生表中表示,无论它们是否在外部查询中引用

这可能会导致一些重大的性能问题,特别是当我们不了解MySQL如何处理语句时(而且MySQL处理语句的方式与其他关系数据库(如Oracle和SQL Server)明显不同)

您可能听过一条建议“避免在MySQL中使用视图”。这条一般性建议(适用于“存储”视图和“内联”视图)背后的原因是可能会不必要地引入的重大性能问题

例如,对于此查询:

SELECT q.name
  FROM ( SELECT h.*
           FROM huge_table h
       ) q
 WHERE q.id = 42
MySQL不会将谓词
id=42
向下“推”到视图定义中。MySQL首先运行内联视图查询,并基本上创建一个
maging_table
的副本,作为一个未索引的MyISAM表。完成后,外部查询将扫描该表的副本,以找到满足谓词的行

如果我们改为重新编写查询,将谓词“推”到视图定义中,如下所示:

SELECT q.name
  FROM ( SELECT h.*
           FROM huge_table h
          WHERE h.id = 42
       ) q
我们希望从视图查询返回的结果集要小得多,派生表也应该小得多。MySQL还能够有效地利用大型_表(id)上的索引
。但是,具体化派生表仍然会带来一些开销

如果我们从视图定义中删除了不必要的列,那么效率会更高(特别是当有很多列、有任何大列或内存引擎不支持数据类型的列时):

完全消除内联视图将更有效:

SELECT q.name
  FROM huge_table q
 WHERE q.id
我不能为MySQL说话——更不用说它可能因存储引擎和MySQL版本而异,但对于PostgreSQL:

PostgreSQL将把它展平为一个查询。内部的
ORDER BY
不是问题,因为添加或删除谓词不会影响其余行的顺序

它将变平为:

select *
from table1 t1
join table2 t2 using (entity_id)
where foo.name = ?
order by t2.sort_order, t1.name;
然后连接谓词将进行内部转换,生成与SQL对应的计划:

select t1.col1, t1.col2, ..., t2.col1, t2.col2, ...
from table1 t1, table2 t2 
where 
   t1.entity_id = t2.entity_id
   and foo.name = ?
order by t2.sort_order, t1.name;
具有简化模式的示例:

regress=> CREATE TABLE demo1 (id integer primary key, whatever integer not null);
CREATE TABLE
regress=> INSERT INTO demo1 (id, whatever) SELECT x, x FROM generate_series(1,100) x;
INSERT 0 100
regress=> EXPLAIN SELECT *
FROM (
    SELECT *
    FROM demo1
    ORDER BY id
) derived
WHERE whatever % 10 = 0;
                        QUERY PLAN                         
-----------------------------------------------------------
 Sort  (cost=2.51..2.51 rows=1 width=8)
   Sort Key: demo1.id
   ->  Seq Scan on demo1  (cost=0.00..2.50 rows=1 width=8)
         Filter: ((whatever % 10) = 0)
 Planning time: 0.173 ms
(5 rows)
…与以下计划相同:

EXPLAIN SELECT *
FROM demo1
WHERE whatever % 10 = 0
ORDER BY id;
                        QUERY PLAN                         
-----------------------------------------------------------
 Sort  (cost=2.51..2.51 rows=1 width=8)
   Sort Key: id
   ->  Seq Scan on demo1  (cost=0.00..2.50 rows=1 width=8)
         Filter: ((whatever % 10) = 0)
 Planning time: 0.159 ms
(5 rows)
如果内部查询中存在
限制
偏移量
、窗口函数或某些其他阻止限定符下推/上拉/展平的因素,则PostgreSQL将认识到它无法安全展平内部查询。它将通过具体化内部查询或迭代其输出并将其提供给e外部查询


视图也是如此。PostgreSQL将在安全的情况下将视图串联并展平到包含查询中。

Wow,真的吗?MySQL中没有限定符上拉/下推?“MySQL将实际创建索引”。我严重怀疑MySQL在查询执行过程中会自动为物化表动态创建索引。CraigRinger:没错。在MySQL中,谓词不会被推送到视图查询中,这与我们在其他数据库引擎中预期的行为大不相同。@ErwinBrandstetter:我想我在什么地方见过这种情况MySQL已经添加或正在添加(在5.6、5.7版本中?或者可能是MariaDB?)一个功能,当优化器检测到它会提高性能时,它会自动在派生表上创建索引。(我目前没有这个参考。)我确信在5.5版和更早版本中没有为派生表创建索引。@ErwinBrandsetter:它在MySQL 5.6参考手册8.2.1.18.3中,从MySQL 5.6.3开始……“在查询执行期间,优化器可能会向派生表添加索引,以加快从派生表中检索行的速度。”@spencer7593:这是当之无愧的投票。深度链接实际上回答了这个问题的大部分:请不要将非常特定于DBMS的问题发布为一般的跨DBMS问题。如果它不是特定于DBMS的
EXPLAIN SELECT *
FROM demo1
WHERE whatever % 10 = 0
ORDER BY id;
                        QUERY PLAN                         
-----------------------------------------------------------
 Sort  (cost=2.51..2.51 rows=1 width=8)
   Sort Key: id
   ->  Seq Scan on demo1  (cost=0.00..2.50 rows=1 width=8)
         Filter: ((whatever % 10) = 0)
 Planning time: 0.159 ms
(5 rows)