首页 > 解决方案 > 在 MySQL 视图中,以 union 开头还是以 union 结尾更快?

问题描述

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

例如

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。

标签: mysqlperformanceview

解决方案


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

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

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

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

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

从 5.7.6 变更日志

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

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

UNION5.7.3 中的优化:

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


推荐阅读