为啥对三个表的联合 mysql 查询比在不可能的 where 子句上连接更快?
Posted
技术标签:
【中文标题】为啥对三个表的联合 mysql 查询比在不可能的 where 子句上连接更快?【英文标题】:Why is a union mysql query over three tables faster than join on impossible where clauses?为什么对三个表的联合 mysql 查询比在不可能的 where 子句上连接更快? 【发布时间】:2016-11-28 22:12:12 【问题描述】:我的架构设置为具有三个表player
coach
和manager
,其中三个表都有一个表employee
的外键,其中包含不超过一个自动递增ID 和一个字符串type
代表他们的员工类型,即。 “球员”或“教练”或“经理”。
但是,不同的员工根据他们工作的团队有不同的 ID。所以我有一个查找表team_x_lookup
用于每个团队(其中 x 是团队编号或名称),它将团队 ID 映射到全局 ID。此外,对于每个包含团队 ID 的团队,我在每个 player
coach
和 manager
表中都有一个生成的列,该列被索引。如果员工不在该团队中,则此列显然为空。
要从员工的团队 ID 中获取员工,我目前有两个选择语句
SELECT * FROM employee e
LEFT JOIN player p ON (e.`type` = 'PLAYER' AND p.employee_id = e.id)
LEFT JOIN coach c ON (e.`type` = 'COACH' AND c.employee_id = e.id)
LEFT JOIN manager m ON (e.`type` = 'MANAGER' AND m.employee_id = e.id)
WHERE e.id = (
SELECT employee_id FROM team_x_lookup t WHERE t.team_id = 6
);
SELECT * FROM (
SELECT * FROM player WHERE team_id = 6
UNION
SELECT * FROM coach WHERE team_id = 6
UNION
SELECT * FROM manager WHERE team_id = 6
) as emp;
我对所有我执行 SELECT 的操作都有索引。运行解释分别给了我这些:
1 PRIMARY e const PRIMARY,id_UNIQUE PRIMARY 4 const 1 100.00
1 PRIMARY p const PRIMARY,employee_id _UNIQUE PRIMARY 4 const 1 100.00
1 PRIMARY c const PRIMARY,employee_id _UNIQUE PRIMARY 4 const 0 0.00 unique row not found
1 PRIMARY m const PRIMARY,employee_id _UNIQUE PRIMARY 4 const 0 0.00 unique row not found
2 SUBQUERY t const PRIMARY,team_id_UNIQUE PRIMARY 4 const 1 100.00
1 PRIMARY <derived2> ALL 6 100.00
2 DERIVED player ref team_x_id_INDEX team_x_id_INDEX 5 const 1 100.00 Using index
3 UNION coach ref team_x_id_INDEX team_x_id_INDEX 5 const 1 100.00 Using index
4 UNION manager ref team_x_id_INDEX team_x_id_INDEX 5 const 1 100.00 Using index
N UNION RESULT <union2,3,4> ALL Using temporary
我不喜欢第二种方式,因为它需要我为每个表增加 20 列。但是,我不明白联合查询如何比查找表查询快 50%!联合不是必须在所有三个表上进行选择,而交叉引用查询会注意到三个连接之一是可能的并丢弃另外两个?
我想知道如何使交叉引用表更快,另外因为联合要求我从联合中的每个表中选择相同数量的列,而我的每个表都有不同数量的列,所有这些都应该是返回。
编辑
我在数据库中有大约 30,000 个元素,我正在通过联合查询数据的前半部分和通过联接查询数据的后半部分来进行计时。我的时间大约为 union 3.9s 和 join 7.0s。
【问题讨论】:
请给DDL。阅读并采取行动minimal reproducible example。搜索Stack Overflow re bad idea“智能键”,在键值中编码信息。 team_x_lookup 也是一个坏主意,您在表名中编码信息。只需从简单的设计开始,其中所有信息都记录为表格行中的值。每个表都有一个相关联的谓词(句子模板),并包含一些行,这些行说明了列值替换列名时的情况。 PS 您对 NULL 的使用似乎会使您的表格超出必要的范围,每一行都需要进行不必要的计算。 【参考方案1】:您可能可以通过删除子查询使第一个查询更高效,如下所示:
SELECT e.* FROM employee e
INNER JOIN team_x_lookup t ON e.id = t.employee_id
LEFT JOIN player p ON (e.`type` = 'PLAYER' AND p.employee_id = e.id)
LEFT JOIN coach c ON (e.`type` = 'COACH' AND c.employee_id = e.id)
LEFT JOIN manager m ON (e.`type` = 'MANAGER' AND m.employee_id = e.id)
WHERE t.team_id = 6
【讨论】:
谢谢,这使查询更简单,但不会改变执行时间 还不错。通常子查询可能是一个问题,但在这种情况下显然不是。以上是关于为啥对三个表的联合 mysql 查询比在不可能的 where 子句上连接更快?的主要内容,如果未能解决你的问题,请参考以下文章