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