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

时间:2014-05-07 10:26:09

标签: mysql sql

我有两张桌子。在表格 UnRevisedTable 中输入原始数据,在表格​​ RevisedTable 中,只有人类在 UnRevisedTable中找到值时插入的修订值条目比他不喜欢。

UnRevisedTable 中,每分钟都有一个条目,在 RevisedTable 中, UnRevisedTable 中的每个不需要的条目都有一个条目。

这两个查询的目的是相同的:在修订数据时,向我展示修订数据和未修改数据的联合,以替换未经修改的数据。

我开始编写query2但它太慢了。然后我写了query1,查询1更快,更快。

我的问题是为什么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;

这里提到的Abhik Chakraborty是解释query1并解释query2:

QUERY1:

+----+-------------+-------+--------+---------------+---------+---------+------------------------+------+-------------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref                    | rows | Extra       |
+----+-------------+-------+--------+---------------+---------+---------+------------------------+------+-------------+
|  1 | SIMPLE      | o     | range  | PRIMARY       | PRIMARY | 8       | NULL                   |    9 | Using where |
|  1 | SIMPLE      | r     | eq_ref | PRIMARY       | PRIMARY | 8       | Mydb.o.start_date_time |    1 |             |
+----+-------------+-------+--------+---------------+---------+---------+------------------------+------+-------------+

QUERY2:

+----+--------------+------------+-------+---------------+---------+---------+------+------+---------------------------------+    
| 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 |                                 |
+----+--------------+------------+-------+---------------+---------+---------+------+------+---------------------------------+

2 个答案:

答案 0 :(得分:2)

首先,这两个查询不会做同样的事情。

  • 第一个查询仅返回UnrevisedTable的时间。如果RevisedTable中的某些时间不在Unrevised,则您将无法获得它们。
  • 第一个查询是使用join。并且,如果您在连接键start_date_time上有索引,那么将使用索引。聚合不太可能使用索引。
  • 第一个查询不会删除每个表中可能存在的重复项。第二个。
  • 当两个表中存在匹配时,两个查询不一定会返回相同的value

第二个查询正在进行两次聚合,但没有连接。第一个聚合用于删除重复值(对于union),第二个聚合用于删除外部group by

我首先修改第二个查询:

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

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

答案 1 :(得分:1)

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

您可能希望考虑将COALESCE替换为查询1中的CASE语句,该语句将返回第一个非空值。它将使查询更容易阅读并且可以更快地运行。

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;