使用联合或左联接从多个表中获取结果

时间:2019-07-19 10:06:06

标签: mysql sql

我有booking列,其中有booking_idbooking_type列。该表与具有外键booking_taxi的{​​{1}}和booking_bus表链接。

booking_id:- booking

booking_id | booking_type:- booking_taxi

booking_taxi_id | booking_id | booking_date:- booking_bus

我想出了两个查询,以获取具有相应预订日期的所有预订。

查询1:

booking_vus_id | booking_id | booking_date

查询2:

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;

哪一个性能更好?

5 个答案:

答案 0 :(得分:1)

首先,如果您想了解相对性能,则应运行查询,以查看哪种查询在 系统上的您的数据上表现更好。您可以从explain获取信息。

第二,查询不相同。他们可能会发生以在您的数据上产生相同的结果集。但是他们不能保证。特别是,第二个删除重复的值(由于union),第一个不删除。

如果没有其他信息,我希望第一个具有更好的性能,特别是因为第二个会产生删除重复值的开销。但是,这需要进行测试。

此外,第一个将返回非12的预订值。 (我假设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_id is null,因此第二个join过滤出第一个匹配的行(这实际上是多余的,因为booking_type上的过滤器执行相同的操作)。
  • where条件仅返回匹配项。

答案 1 :(得分:1)

嵌套联接是一种将一个表中的每个记录与另一个表中的每个记录进行比较的联接。如果一个表中有M,第二个表中有N,则复杂度变为MxN。

基于该理论,使用并集的第二个查询将更有效

答案 2 :(得分:1)

首先想到的是:数据模型合适吗?公共汽车和出租车的预订有很大不同吗?一次预订真的包含在不同日期的一种车辆类型的多次预订吗?

  • 预订:booking_id | booking_date | vehicle_id |行程日期
  • 车辆:vehicle_id |车辆类型| id_company | ...

例如可能更合适。如果找到更合适的数据模型,查询数据将变得更加容易。

关于您当前的数据模型和查询:

  • 查询表明您的数据模型允许不一致。您可以预订类型2,但可以预订与之相关的bbus,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;

答案 3 :(得分:0)

您可以在sqlserver中看到queryplan和查询的性能。

但是,当您使用联接时,如果您的表按索引sql进行排序,则将它们与嵌套联接进行比较,因此,当您使用primarykey和forigenkey创建表时,联接性能良好,您可以使用某些索引来获得更好的性能,但首先要使用联合sqlengine获取第一个查询的结果并对其进行排序,然后再获取第二个查询结果并对其进行排序和compaire结果,并删除重复数据,因此绝对联接比union更好。

答案 4 :(得分:0)

似乎使用Union All的查询要比使用Left连接的查询要快(至少在这种情况下如此)。

左联接查询运行三次完整扫描(带有嵌套循环)

Explain Left Join

但是使用联合全部只有两个表扫描

Explain Union All