Mysql 来自两个表的Sql查询:消耗的时间

Mysql 来自两个表的Sql查询:消耗的时间,mysql,sql,Mysql,Sql,我有两张桌子。在表不可修改的中有原始数据,在表修订表中只有修订值的条目,当人类在不可修改的中发现一个他不喜欢的值时,才会插入这些条目 在不可修改的中,每分钟有一个条目;在可修改的中,每一个不需要的条目都有一个条目 这两个查询的目的是相同的:显示修订数据和未修订数据的并集,在有修订数据时替换未修订数据 我开始写这个问题,但速度太慢了。然后我写了query1,query1的速度要快得多 我的问题是为什么query1比query2快?Thx query1: SELECT o.start_dat

我有两张桌子。在表不可修改的中有原始数据,在表修订表中只有修订值的条目,当人类在不可修改的中发现一个他不喜欢的值时,才会插入这些条目

不可修改的中,每分钟有一个条目;在可修改的中,每一个不需要的条目都有一个条目

这两个查询的目的是相同的:显示修订数据和未修订数据的并集,在有修订数据时替换未修订数据

我开始写这个问题,但速度太慢了。然后我写了query1,query1的速度要快得多

我的问题是为什么query1比query2快?Thx

query1:
    SELECT o.start_date_time,
        CASE WHEN r.start_date_time IS NULL THEN o.value ELSE r.value END AS value,
        FROM UnRevisedTable o LEFT JOIN RevisedTable r ON o.start_date_time = r.start_date_time
        WHERE o.start_date_time >= '".$start."' AND o.start_date_time < '".$finish."' ORDER BY start_date_time ASC;

query2:
    select * from(
      select RevisedTable.* from RevisedTable where start_date_time between '".$start."' and '".$finish."' 
          union 
      select UnRevisedTable.* from UnRevisedTable where start_date_time between '".$start."' and '".$finish."'
    ) as t1 group by start_date_time;
问题2:

+----+--------------+------------+-------+---------------+---------+---------+------+------+---------------------------------+    
| id | select_type  | table      | type  | possible_keys | key     | key_len | ref  | rows | Extra                           |
+----+--------------+------------+-------+---------------+---------+---------+------+------+---------------------------------+
|  1 | PRIMARY      | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL |   14 | Using temporary; Using filesort |
|  2 | DERIVED      | RevisedTable  | range | PRIMARY    | PRIMARY | 8       | NULL |    2 | Using where                     |
|  3 | UNION        | UnRevisedTable| range | PRIMARY    | PRIMARY | 8       | NULL |   10 | Using where                     |
| NULL | UNION RESULT | <union2,3> | ALL   | NULL        | NULL    | NULL    | NULL | NULL |                                 |
+----+--------------+------------+-------+---------------+---------+---------+------+------+---------------------------------+
+------+------+------+------+------+------+------+------+------+------+------+------+-----------+-----------+
|id |选择|类型|类型|可能的|键|键|列|参考|行|额外|
+----+--------------+------------+-------+---------------+---------+---------+------+------+---------------------------------+
|1 | PRIMARY | ALL | NULL | NULL | NULL | NULL | 14 |使用临时命令;使用文件排序|
|2 |导出|修订表|范围|主|主| 8 |空| 2 |使用where|
|3 |并集|不可校正|范围|主|主| 8 |空| 10 |使用where|
|空|并集结果| |全部|空|空|空|空|空||
+----+--------------+------------+-------+---------------+---------+---------+------+------+---------------------------------+

首先,这两个查询的作用不同

  • 第一个查询只返回
    不可修改的
    中的次数。如果
    已修订表中有时间
    而不是
    未修订表中的时间
    ,则无法获取这些时间
  • 第一个查询使用
    联接
    。而且,如果在join键上有一个索引,
    start\u date\u time
    ,则将使用该索引。聚合不太可能使用索引
  • 第一个查询不会删除每个表中可能存在的重复项。第二个是
  • 当两个表中存在匹配项时,这两个查询不一定返回相同的
    
    
第二个查询执行两个聚合,但没有联接。第一个聚合用于删除重复值(用于
联合
),第二个聚合用于外部
分组依据

首先,我将第二个问题修改为:

select start_date_time, max(value) as value
from ((select start_date_time, value
       from RevisedTable
       where start_date_time between '".$start."' and '".$finish."' 
      ) union all
      (select start_date_time, value
       from UnRevisedTable
       where start_date_time between '".$start."' and '".$finish."'
      )
     ) t1
 group by start_date_time

您可能还会发现这比加入
要慢。MySQL引擎在实现连接方面比聚合做得更好。

为了回答您的问题,较慢的查询使用了
联合,它删除了第一个表和第二个表之间重复的行。这将需要一种通常很昂贵的方法。您可以在查询2的计划中看到它是一个文件排序。您可以使用
联合ALL
来消除这种排序

您可以考虑替换查询1中的case语句,其中返回第一个非null。它将使查询更容易阅读,并且可能运行得更快

SELECT 
    o.start_date_time,
    COALESCE (o.value, r.value) AS value
FROM UnRevisedTable o LEFT JOIN RevisedTable r ON o.start_date_time = r.start_date_time
WHERE o.start_date_time >= '".$start."' 
AND o.start_date_time < '".$finish."' 
ORDER BY start_date_time ASC;
选择
o、 开始日期时间,
合并(o值,r值)为值
在o.start\u日期\u时间=r.start\u日期\u时间上从不可修改到左联接已修改表r
其中o.start\u date\u time>='“$start.”
和o.start\u date\u time<'“$finish.”
按开始日期时间ASC订购;

使用
解释第一个查询
,然后使用
解释第二个查询
,并在问题中分享结果。您好。首先,谢谢你的回答。我正在绘制数据,所以我很快发现这两个qiereis不完全相同,你的解释肯定有助于我更好地理解它们。这两个表中的数据量很大(10年,每1分钟输入一个条目)。正如我所说,我正在绘制这些数据,绘制这么多数据是不可能的。我使用这两个查询作为查询的子查询,该查询按时间间隔对数据进行分组。拥有如此复杂的查询和如此大量的数据会使整个过程变慢。我将讨论它的优点和缺点。谢谢你的回答。我打算试试看工会。合并是没有用的,因为数据的修改有时需要将值设置为null。
SELECT 
    o.start_date_time,
    COALESCE (o.value, r.value) AS value
FROM UnRevisedTable o LEFT JOIN RevisedTable r ON o.start_date_time = r.start_date_time
WHERE o.start_date_time >= '".$start."' 
AND o.start_date_time < '".$finish."' 
ORDER BY start_date_time ASC;