在 MySQL 视图中,以 union 开头还是以 union 结尾更快?

Posted

技术标签:

【中文标题】在 MySQL 视图中,以 union 开头还是以 union 结尾更快?【英文标题】:In MySQL view, is it faster to start with union or end with it? 【发布时间】:2018-06-15 07:38:25 【问题描述】:

我的数据库有多个表,其中有一些匹配的列,但名称和顺序不同。

例如

Table1:   FullName Grade Foo
Table2:   Bar Rank WholeName

什么会更快:

1) 1 个视图,对每个表重复相同的查询

CREATE View Test AS
  SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(FullName, ' ', 1), ' ', -1) AS "First Name",
         If (Grade<50, "Bad", "Good") AS "Type"
    FROM table1
  UNION
  SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(WholeName, ' ', 1), ' ', -1) AS "First Name",
         If (Rank<50, "Bad", "Good") AS "Type"
    FROM table2

或者

2) 2 个视图,一个用于纯合并,另一个用于操作

CREATE View Test1 AS
SELECT FullName AS "First Name", Grade AS "Type"
FROM table1
UNION
SELECT WholeName AS "First Name", Rank AS "Type"
FROM table2

CREATE View Test2 AS
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(`First Name`, ' ', 1), ' ', -1) AS "First Name",
If (Type<50, "Bad", "Good") AS "Type"
FROM Test1

显然 1) 更复杂,因为您必须重复每个操作。如果你有 10 张桌子,那就意味着重复同样的操作 10 次。如果你有 10 个操作,那就意味着要编写 100 个操作而不是 10 个。但如果它更快,我会接受。

http://www.sqlfiddle.com/#!9/48d531/1 建议的时间大致相同,尽管在某些运行中它倾向于 2)。

请记住,其中涉及大量数据,实际 SQL 非常复杂,并且涉及 LEFT JOIN。

【问题讨论】:

无视图 > 1 视图 > 2 视图。每个级别的视图都将限制 mysql 优化查询的选项(例如,在评估每一行之前使用索引或连接或过滤)。您正在尝试通过应用视图来修复您的数据库模型,这将变得混乱/缓慢。想法:a)将名称直接存储在 2 个字段中 b)将所有名称存储在“用户”表中,并在 2 个表中使用 id(删除 union)c)在中显示内容(“好”/“坏”)您的前端或最外面的查询。现在您有 0 次观看。如果实际的 sql 更复杂,则类似的修复/注意事项更加相关。 修复模型是对的,但表来自不同的来源,具有不同的列名。对我来说,比 1 个视图快于 2 个视图听起来很合理,那么 sqlfiddle 怎么会显示我写的内容呢?不知道 a) 和 b) 是什么意思,也许用 sqlfiddle 来演示?不知道为什么 c) 会更快,SQL 是在服务器中完成的,所以我认为使用另一个服务器过程甚至更糟的是客户端没有任何好处。 20 行表的执行时间除了随机中断如何影响执行时间之外,不会为您提供任何有价值的信息。视图(在 mysql 中)不能比非视图快,它只是缩短了 sql 代码:视图的代码实际上会放在您使用视图的任何地方。我的意思是:您当然可以使用视图来修复您的模型(例如,动态拆分名称而不是首先在 2 列中的“名字”、“姓氏”),但正如您已经看到的那样,它使事情其实更复杂。每次优化的第一步都是干净的数据和干净的数据模型。 【参考方案1】:

VIEW 是语法糖——试试等效的SELECT

“糖”论点说在解决VIEWs之后Q2是这样的:

    SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(`First Name`,
               ' ', 1), ' ', -1) AS "First Name",
           If (Type<50, "Bad", "Good") AS "Type"
    FROM ( SELECT .. UNION SELECT .. )

FROM ( ... ) 被称为“派生”表。它通常会变成一个临时表,从中执行其余的选择。这是第一季度避免的额外的、中等重量级的步骤。

实际上,您可能不会注意到性能差异。

From the 5.7.6 ChangeLog:

为了处理派生表(FROM 子句中的子查询)或视图引用,优化器可以将派生表或视图引用具体化到内部临时表或将其合并到外部查询块中。以前,派生表总是被物化,而等效的视图引用有时被物化,有时被合并。这种对等价查询的不一致处理可能会导致性能问题:不必要的派生表实现需要时间并阻止优化器将条件下推到派生表。

这意味着您问题的答案取决于您使用的 MySQL 版本。

UNION optimization in 5.7.3:

服务器不再为满足特定条件的 UNION 语句使用临时表。相反,它从临时表创建中只保留执行结果列类型转换所需的数据结构。该表未完全实例化,并且没有向其中写入或读取任何行;行直接发送到客户端。结果是减少了内存和磁盘需求,并且在将第一行发送到客户端之前的延迟更小,因为服务器不需要等到最后一个查询块被执行。 EXPLAIN 和优化器跟踪输出将更改:UNION RESULT 查询块将不存在,因为该块是从临时表中读取的部分。 ... Bug #50674

【讨论】:

5.6.39,但请记住直到version 5.7.7 Views 不支持 FROM 子句中的子查询,这就是为什么我没有在问题中包含此选项的原因。没有它,你的答案仍然适用吗? @LWC - 感谢您指出这一点。我改写了我的答案以避免那个“错误”。 谢谢!但是我已经添加了指向您报价的链接,并且看到下一行是 优化器现在以一致的方式处理派生表;也就是说,与视图引用相同。 这是否意味着我的问题的答案不依赖于 MySQL 版本(至少在您的意思的上下文中)? @LWC - UNION 增加了额外的皱纹。您能否提供EXPLAIN EXTENDED SELECT ...; SHOW WARNINGS;,以便我们讨论(我希望)5.7.7“改进”缺乏或存在的影响。 @LWC - 另外,我不相信只有几毫秒的时间 - 更多数据可能导致不同的查询计划;外部流程可能会影响时间;等等

以上是关于在 MySQL 视图中,以 union 开头还是以 union 结尾更快?的主要内容,如果未能解决你的问题,请参考以下文章

mysql的unionleft join right join inner join和视图学习

如何使用 UNION 和子 SELECT 从查询构造 MySQL 视图

MySQL监控分析视图 -Sys Schema的基本使用

MySQL监控分析视图 -Sys Schema的基本使用

MySQL监控分析视图 -Sys Schema的基本使用

如何删除所有以某个前缀开头的 MySQL 表?