MySQL 通过使用连接查询来优化联合查询

标签 mysql join union

我有 3 张表 - 一张用于用户,一张用于收款,一张用于收款。我想在单个结果集中显示所有收款和付款。我可以用多个 select 和一个 union 来做到这一点,但它看起来很麻烦,而且我怀疑它的速度很慢是因为子查询 - 而且表非常大(虽然我使用索引)。有没有更快的方法来实现这一目标?也许使用全外连接

这是带有一些示例数据的架构的简化版本:

create table users (
  id int auto_increment,
  name varchar(20),
  primary key (id)
) engine=InnoDB;
insert into users (name) values ('bob'),('fred');

create table user_incoming_payments (
  user_id int,
  funds_in int
) engine=InnoDB;
insert into user_incoming_payments
values (1,100),(1,101),(1,102),(1,103),
(2,200),(2,201),(2,202),(2,203);

create table user_outgoing_payments (
  user_id int,
  funds_out int
) engine=InnoDB;
insert into user_outgoing_payments
values (1,100),(1,101),(2,200),(2,201);

这是为用户 bob 生成我想要的结果的丑陋查询:

select * from (
 (select u.name, i.funds_in, 0 as 'funds_out' from users u
 inner join user_incoming_payments i on u.id = i.user_id)
 union
 (select u.name, 0 as 'funds_in', o.funds_out from users u
 inner join user_outgoing_payments o on u.id = o.user_id)
) a where a.name = 'bob'
order by a.funds_in asc, a.funds_out asc;

这里是我可以用 join 做同样的事情的最接近结果——尽管它不正确,因为我希望这个结果集看起来和以前的一样,但我没有确定如何使用全外连接:

select *
from users u
right join user_incoming_payments i on u.id = i.user_id
right join user_outgoing_payments o on u.id = o.user_id
where u.name = 'bob';

SQL Fiddle here

最佳答案

MySQL 不支持FULL OUTER JOIN。即使它确实支持它,我认为您也不会想要它,因为它会引入半笛卡尔积...... incoming_ 中的每一行都与 outgoing_< 中的每一行相匹配,创建额外的行。

如果 incoming_ 有四行,outgoing_ 有六行,则连接操作生成的集合将包含 24 行。

这看起来更像是您想要的集合串联操作。也就是说,您有两个要连接在一起的独立集合。这不是 JOIN 操作。这是一个 UNION ALL 集合操作。

SELECT ... FROM ... 
 UNION ALL
SELECT ... FROM ...

如果您不需要删除重复项(在这种情况下您似乎不想这样做,如果 incoming_ 中有多行具有相同的 funds_in 值,我认为您不想删除任何行。)...

然后使用 UNION ALL 集合运算符,它执行检查和删除重复行。

UNION 运算符删除重复的行。哪个(再次)我认为你不想要。


派生表不是必需的。

而且 MySQL 不会将谓词从外表“推”到内联 View 中。这意味着 MySQL 将为 所有 用户实现一个包含所有传入和传出的派生表。外部查询将通过它来查找行。在 MySQL 的最新版本之前,没有在派生表上创建索引。

有关更高效查询的示例,请参阅 Strawberry 的回答。

对于小样本集,索引不会产生任何影响。但是,如果集合很大,您将需要添加适当的覆盖索引。

另外,对于这样的查询,我倾向于包含一个鉴别器列,告诉我哪个查询返回了一行。

 (
   SELECT 'i' AS src
        , ...
     FROM ...
 )
   UNION ALL
 (
   SELECT 'o' AS src
        , ...
     FROM ...
 )
   ORDER BY ...

关于MySQL 通过使用连接查询来优化联合查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38111982/

相关文章:

php - pcntl_fork 和 MySQL 连接消失了

mysql - 从一个别名中选择多列

sql - Oracle FETCH FIRST 1 ROW with UNION ALL 语句

mysql - 我如何联合并找到这个原始 SQL 调用的中位时间?

mysql - 从文本/url 快速生成数字 id "SELECT"

mySQL语法不起作用

mysql - 删除列的值,然后按升序排列值

mysql - SQL MYSQL 多表查询连接

mysql - MySql 中连接 4 个表时出现重复数据

android - 按不在结果集中的术语排序