MySQL匹配datetime-range的datetime需要

时间:2017-01-11 22:04:47

标签: mysql sql datetime range

我在MySQL-Server(InnoDB)上有两个表。 两者都有一个datetime-field,每行包含一个测量值。 表A中的测量每分钟进行一次,表B中的测量每秒进行一次。

现在我想选择表B中测量的Min(),在表A中测量时间为+/- 30秒,并用表A中的测量结果显示。

当我查找EQUAL时间码时,查询将在大约一秒钟内完成。

但是当我尝试用以下语句选择它们时:

SELECT min(tableB.measurement),tableA.* 
FROM tableA,tableB
WHERE tableA.timecode BETWEEN DATE_SUB(tableB.timecode,INTERVAL 30 SECOND) and  DATE_ADD(tableB.timecode,INTERVAL 30 SECOND)
GROUP BY tableA.timecode;

然后查询将永远运行(或者至少直到它达到MySQL Workbench的超时时间,我将其设置为超过一小时)

所以数据的结果如

table A
|timecode|measurement|
|15:00:30|    5      |
|15:10:30|    6      |

table B
|timecode|measurement|
|15:00:29|    105    |
|15:00:31|    56     |
|15:10:28|    25     |
|15:10:32|    16     |

应该导致s.th喜欢

|min(tableB.measurement)| timecode  |  measurement|
|       56              | 15:00:30  |      5      |
|       16              | 15:10:30  |      6      |

我实际上误用了SQL来处理大量的表格数据(我可能不会改变)。我知道这不是你应该做的,但我发现没有其他选择来应对这个1500万行数据集...... 两个datetime-fields都有一个索引BTW ...

希望得到帮助, 罗伯特

这里是建议查询的EXPLAIN:

 id   select_type   table   partitions   type   possible_keys   key   key_len   ref   rows   filtered   Extra 
 1   PRIMARY         a         ALL           125953   100.00   
 2   DEPENDENT  SUBQUERY   b     ALL   idx_xc_timecode_trans,idx_xc_timecode_trans_measurement         15755656   11.11   
Range  checked  for  each  record  (index  map:  0x60) 

更新: SQL Workbench中的visual EXPLAIN只显示了s.th的成本,如

select * where tableA.timecode = tableB.timecode

是~160.000

而sth喜欢

select * where tableA.timecode  between DATE_SUB( tableB.timecode, interval 30 second) and DATE_ADD(tableB.timecode, interval 30 second)

是~99.600.000.000 !!!

这是否意味着这可能是不可行的任务?这是一个不常见的"查询(根据"这不是DBMS的用途")

3 个答案:

答案 0 :(得分:0)

只要tableB.measurement被编入索引,就可以使用以下查询:

SELECT (
        SELECT b.measurement
        FROM tableB b
        WHERE b.timecode BETWEEN a.timecode - INTERVAL 30 SECOND
          AND a.timecode + INTERVAL 30 SECOND
        ORDER BY b.timecode
        LIMIT 1
    ) AS MinB,
     a.timecode,
     a.measurement
FROM tableA a
/*GROUP BY a.timecode*/

更新

您希望MIN(b.measurement)而不是MIN(b.timecode),因此可以简化查询:

SELECT (
        SELECT MIN(b.measurement)
        FROM tableB b
        WHERE b.timecode BETWEEN a.timecode - INTERVAL 30 SECOND
          AND a.timecode + INTERVAL 30 SECOND
    ) AS MinB,
     a.timecode,
     a.measurement
FROM tableA a

答案 1 :(得分:0)

您在TableB中添加或减去时间码datetime值,但未指定INTERVAL。

SELECT min(tableB.timecode),tableA.* 
FROM tableA,tableB
WHERE tableA.timecode < DATE_ADD(tableB.timecode, + INTERVAL 30 SECOND) and tableA.timecode > DATE_ADD(tableB.timecode, INTERVAL -30 SECOND);

答案 2 :(得分:0)

无法对此进行测试,但是将时间码四舍五入到子查询中的最近分钟,并且仅加入时间码可能会很好地执行:

SELECT b.measurement,tableA.* 
FROM tableA a
JOIN (SELECT SEC_TO_TIME((ROUND(TIME_TO_SEC(timecode)/60)) * 60 as timecode
            ,MIN(measurement) as measurement
      FROM tableB
      GROUP BY SEC_TO_TIME((ROUND(TIME_TO_SEC(timecode)/60)) * 60
      )b
 ON a.timecode = b.timecode

由于舍入不会,您可以查看TIMESTAMPDIFF(second,a.timecode,b.timecode)的效果是否优于当前加入:

SELECT min(b.measurement),a.timecode,a.measurement
FROM tableA a
JOIN tableB b
 ON ABS(TIMESTAMPDIFF(second,a.timecode,b.timecode)) < 30
GROUP BY a.timecode,a.measurement;