Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 使用union或left join从多个表中获取结果_Mysql_Sql - Fatal编程技术网

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
    条件仅返回匹配项

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


基于这一理论,使用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不太可能做到这一点,但这是可能的。)