mysql连接子查询

标签 mysql optimization join groupwise-maximum

我有以下表格:

CREATE TABLE `data` (
  `date_time` decimal(26,6) NOT NULL,
  `channel_id` mediumint(8) unsigned NOT NULL,
  `value` varchar(40) DEFAULT NULL,
  `status` tinyint(3) unsigned DEFAULT NULL,
  `connected` tinyint(1) unsigned NOT NULL,
  PRIMARY KEY (`channel_id`,`date_time`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

CREATE TABLE `channels` (
  `channel_id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
  `channel_name` varchar(40) NOT NULL,
  PRIMARY KEY (`channel_id`),
  UNIQUE KEY `channel_name` (`channel_name`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

我想知道是否有人可以就如何优化或重写以下查询给我一些建议:

SELECT channel_name, t0.date_time, t0.value, t0.status, t0.connected, t1.date_time, t1.value, t1.status, t1.connected FROM channels,
    (SELECT MAX(date_time) AS date_time, channel_id, value, status, connected FROM data
        WHERE date_time <= 1300818330
        GROUP BY channel_id) AS t0
    RIGHT JOIN
    (SELECT MAX(date_time) AS date_time, channel_id, value, status, connected FROM data
        WHERE date_time <= 1300818334
        GROUP BY channel_id) AS t1
ON t0.channel_id = t1.channel_id
WHERE channels.channel_id = t1.channel_id

基本上,我在两个不同的时间获取每个 channel_name 的值、状态和连接字段。由于 t0 始终 <= t1,因此 t1 可能存在字段,但 t0 不存在,我希望显示该字段。这就是我使用 RIGHT JOIN 的原因。如果它对于 t1 不存在,那么它对于 t0 也不存在,因此不应返回任何行。

问题好像是因为我是加入子查询,不能用索引?我尝试重写它以首先对数据表的 channel_id 进行自连接,但那是数百万行。

当 t0.value = t1.value & t0.status = t1.status & t0.connected = t1.connected 时,能够向最后一行添加一个 bool 字段也很好。

非常感谢您的宝贵时间。

最佳答案

您可以将两个子查询缩减为一个

SELECT channel_id,
   MAX(date_time) AS t1_date_time,
   MAX(case when date_time <= {$p1} then date_time end) AS t0_date_time
FROM data
WHERE date_time <= {$p2}
GROUP BY channel_id

GROUP BY 在 MySQL 中是出了名的误导。想象一下,如果您在同一个选择中有 MIN() 和 MAX(),那么未分组的列应该来自哪一行?一旦理解了这一点,您就会明白为什么它不是确定性的。

获取完整的 t0 和 t1 行

SELECT x.channel_id,
       t0.date_time, t0.value, t0.status, t0.connected,
       t1.date_time, t1.value, t1.status, t1.connected
FROM (
    SELECT channel_id,
       MAX(date_time) AS t1_date_time,
       MAX(case when date_time <= {$p1} then date_time end) AS t0_date_time
    FROM data
    WHERE date_time <= {$p2}
    GROUP BY channel_id
) x
INNER JOIN data t1 on t1.channel_id = x.channel_id and t1.date_time = x.t1_date_time
LEFT JOIN data t0 on t0.channel_id = x.channel_id and t0.date_time = x.t0_date_time

最后是获取 channel 名称的连接

SELECT c.channel_name,
       t0.date_time, t0.value, t0.status, t0.connected,
       t1.date_time, t1.value, t1.status, t1.connected,
       t0.value=t1.value AND t1.status=t0.status
                         AND t0.connected=t1.connected name_me
FROM (
    SELECT channel_id,
       MAX(date_time) AS t1_date_time,
       MAX(case when date_time <= {$p1} then date_time end) AS t0_date_time
    FROM data
    WHERE date_time <= {$p2}
    GROUP BY channel_id
) x
INNER JOIN channels c on c.channel_id = x.channel_id
INNER JOIN data t1 on t1.channel_id = x.channel_id and t1.date_time = x.t1_date_time
LEFT JOIN data t0 on t0.channel_id = x.channel_id and t0.date_time = x.t0_date_time


编辑

要对 channel 名称执行 RLIKE,在 c.channel_name 的查询末尾添加一个 WHERE 子句看起来很简单。然而,在子查询中过滤它可能会执行得更好,利用 MySQL 从左到右处理逗号连接的特性。

SELECT x.channel_name,
       t0.date_time, t0.value, t0.status, t0.connected,
       t1.date_time, t1.value, t1.status, t1.connected,
       t0.value=t1.value AND t1.status=t0.status
                         AND t0.connected=t1.connected name_me
(
    SELECT c.channel_id, c.channel_name,
       MAX(d.date_time) AS t1_date_time,
       MAX(case when d.date_time <= {$p1} then d.date_time end) AS t0_date_time
    FROM channels c, data d
    WHERE c.channel_name RLIKE {$expr}
      AND c.channel_id = d.channel_id
      AND d.date_time <= {$p2}
    GROUP BY c.channel_id
) x
INNER JOIN data t1 on t1.channel_id = x.channel_id and t1.date_time = x.t1_date_time
LEFT JOIN data t0 on t0.channel_id = x.channel_id and t0.date_time = x.t0_date_time

关于mysql连接子查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5399678/

相关文章:

php - 我如何在mysql中使用函数

php - 图像保存到文件夹但路径未保存在sql中

java - 从列表 : old approach vs stream design thought? 中删除重复项

SQL 理解外连接与条件以及为什么条件的顺序可以改变结果

sql - 优化大型表上的 SQL 连接

java - 无法执行语句; SQL [不适用];约束[主要];嵌套异常是 org.hibernate.exception.ConstraintViolationException

phpmyadmin : no database selected

c - 为什么mulss在Haswell上只需要3个周期,而不是Agner的指令表? (使用多个累加器展开FP循环)

c++ - 哪个是查找速度最快的 STL 容器?

java - JPA Criteria API 任意数量的联接/子查询