Mysql 使用union或left join从多个表中获取结果
我有Mysql 使用union或left join从多个表中获取结果,mysql,sql,Mysql,Sql,我有booking表,表中有booking\u id,booking\u type列。此表与带有外键的预订出租车和预订公交车表链接预订id 预订:- booking_id|booking_type 预订出租车:- 预订出租车id |预订id |预订日期 预订公交车:- booking_vus_id | booking_id | booking_日期 我提出了两个查询,以获得所有预订以及各自的预订日期 问题1: select bk.booking_id, bk.booking_t
booking
表,表中有booking\u id
,booking\u type
列。此表与带有外键的预订出租车
和预订公交车
表链接预订id
预订
:-
booking_id|booking_type
预订出租车
:-
预订出租车id |预订id |预订日期
预订公交车
:-
booking_vus_id | booking_id | booking_日期
我提出了两个查询,以获得所有预订以及各自的预订日期
问题1:
select bk.booking_id,
bk.booking_type,
case
when booking_type = 3 then bbus.booking_date
when booking_type = 2 then btaxi.pickup_date
end as booking_date
from booking bk
left join booking_taxi btaxi on btaxi.booking_id = bk.booking_id and bk.booking_type = 2
left join booking_bus bbus on bbus.booking_id = bk.booking_id and bk.booking_type = 3;
问题2:
select bk.booking_id,
bk.booking_type,
btaxi.booking_date
from booking bk
inner join booking_taxi btaxi on btaxi.booking_id = bk.booking_id and bk.booking_type = 2
union all
select bk.booking_id,
bk.booking_type,
bbus.booking_date
from booking bk
inner join booking_bus bbus on bbus.booking_id = bk.booking_id and bk.booking_type = 3;
哪一个性能更好?首先,如果您想了解相对性能,那么您应该运行查询,查看哪一个对系统上的数据性能更好。您可以从
explain
获取信息
第二,查询不完全相同。它们可能会在您的数据上产生相同的结果集。但他们并不能保证会这样做。特别是,第二个删除重复值(因为联合
),而第一个不删除
在没有任何其他信息的情况下,我希望第一个具有更好的性能,特别是因为第二个会导致删除重复值的开销。然而,这需要测试
此外,第一个将返回不是1
或2
的预订值。(我假设FROM
子句中的2/3是一个打字错误。)
就个人而言,我更喜欢第一种,尽管我倾向于将其写成:
select bk.booking_id, bk.booking_type,
coalesce(btrain.booking_date, btaxi.pickup_date) as booking_date
from booking bk left join
booking_taxi btaxi
on btaxi.booking_id = bk.booking_id and
bk.booking_type = 1 left join
booking_bus bbus
on bbus.booking_id = bk.booking_id and
bk.booking_type = 2 and
btaxi.booking_id is null
where btaxi.booking_id is not null or
bbus.booking_id is not null;
有三个区别:
而不是coalesce()
。这只是简短易读case
- 条件
,因此第二个btaxi.booking\u id为null
过滤掉第一个匹配的行(这实际上是多余的,因为join
上的过滤器做了相同的事情)booking\u type
条件仅返回匹配项where
基于这一理论,使用union的第二次查询将更加高效您可以在sqlserver中看到queryplan并比较查询的性能
但是当您使用join时,若您的表是用索引sql排序的,那个么请将它们和嵌套联接进行比较,这样当您使用primarykey和forigenkey联接创建表时,可以使用一些索引提高性能,但在union sqlengine中,首先获取第一个查询的结果,然后对其进行排序,然后获取第二个查询结果并对其进行排序,然后进行比较结果并删除重复数据,因此绝对联接比联合好。首先想到的是:数据模型合适吗?公共汽车和出租车的预订量有很大的不同吗?一次预订是否真的包括一种车型在不同日期的多次预订 这个
- 预订:预订| id |预订|日期|车辆| id |行程|日期
- 车辆:车辆| id |车辆|类型| id |公司|
- 查询表明您的数据模型允许不一致。您可以拥有类型2的预订,但与之关联的任何BBU、btaxi、btrain行。您应该找到一种方法来更改您的数据模型,这样就不会发生这种情况
- 只要存在其他预订类型,或者您没有在第一个查询中添加where子句将预订行限制为所需类型,查询就会返回不同的结果
- 两个查询都可以。我觉得第二个读起来好一点。(应该是
当然不是UNION ALL
)UNION[DISTINCT]
UNION ALL
查询:
select booking_id, 2 as booking_type, booking_date from btaxi
union all
select booking_id, 3 as booking_type, booking_date from btrain
order by booking_id, booking_date;
似乎使用UNIONALL的查询比使用左连接的查询要快(至少在这种情况下是这样) 左连接查询运行三次完全扫描(使用嵌套循环) 但是使用UNIONALL只有两个表扫描
运行
explain..
在这两个查询中,您将了解问题所在。另外,只需使用sql\u no\u cache
标志运行这些查询,您就可以自己比较性能。我的猜测是,如果DBMS在可用和适当的地方使用索引,那么第二种方法的性能会更好。在连接中,它通常不读取整个表来查找行,而是使用索引树几乎立即查找行。在这两种查询中,DBMS都需要仅在预订类型=2时查找预订出租车。一旦我们在第一个查询中添加了where bk.booking\u键入(2,3)
,我们就会要求完全相同的数据,DBMS可能会看到这一点,甚至会为两个查询提出相同的执行计划。(无可否认,我认为MySQL不太可能做到这一点,但这是可能的。)