MySQL组通过查询进行子选择优化

时间:2016-03-02 07:24:25

标签: mysql optimization group-by

我在MySQL中有以下表格:

CREATE TABLE `events` (
  `pv_name` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL,
  `time_stamp` bigint(20) unsigned NOT NULL,
  `event_type` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL,
  `value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin,
  `value_type` varchar(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `value_count` bigint(20) DEFAULT NULL,
  `alarm_status` varchar(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `alarm_severity` varchar(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`pv_name`,`time_stamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED;

CREATE TEMPORARY TABLE `matching_pv_names` (
  `pv_name` varchar(60) NOT NULL,
  PRIMARY KEY (`pv_name`)
) ENGINE=Memory DEFAULT CHARSET=latin1;

matching_pv_names表包含唯一events.pv_name值的子集。

使用“松散索引扫描”优化运行以下查询:

SELECT events.pv_name, MAX(events.time_stamp) AS time_stamp
FROM events
WHERE events.time_stamp <= time_stamp_in
GROUP BY events.pv_name;

是否可以通过将events.pv_name值限制为matching_pv_names表中的值而不会丢失'松散索引扫描'优化来改善此查询的时间?

2 个答案:

答案 0 :(得分:0)

尝试使用以下查询之一将输出限制为matching_pv_names中找到的匹配值。

查询1:

SELECT e.pv_name, MAX(e.time_stamp) AS time_stamp
FROM events e
INNER JOIN matching_pv_names pv ON e.pv_name = pv.pv_name
WHERE e.time_stamp <= time_stamp_in
GROUP BY e.pv_name;

查询2:

SELECT e.pv_name, MAX(e.time_stamp) AS time_stamp
FROM events e
WHERE e.time_stamp <= time_stamp_in
AND EXISTS ( select 1 from matching_pv_names pv WHERE e.pv_name = pv.pv_name )
GROUP BY e.pv_name;

我在这里引用manual,因为我认为它适用于你的情况(大胆强调我的):

  

如果WHERE子句包含范围谓词(...),则松散索引扫描会查找每个组的第一个键   满足范围条件,并再次读取最少   可能的键数。这可以在以下情况下进行   条件:

     

查询位于单个表格

知道这一点,我相信查询1将无法使用松散的索引扫描,但可能第二个查询可以做到这一点。如果情况仍然如此,您还可以尝试使用派生表的第三种方法。

查询3:

SELECT e.*
FROM (
  SELECT e.pv_name, MAX(e.time_stamp) AS time_stamp
  FROM events e
  WHERE e.time_stamp <= time_stamp_in
  GROUP BY e.pv_name
  ) e
INNER JOIN matching_pv_names pv ON e.pv_name = pv.pv_name;

答案 1 :(得分:0)

您的查询非常有效。你可以通过这样做来“证明”它:

FLUSH STATUS;
SELECT ...;
SHOW SESSION STATUS LIKE 'Handler%';

大多数数字指的是索引或数据中的“触摸行”。你会看到非常低的数字。如果最大的一个是关于返回的行数,那就非常好了。 (我尝试了类似的查询,得到了大约2倍;我不知道为什么。)

接触了几行,然后

  • 输出行将超过运行时间。那么,谁在乎效率;或
  • 由于跨越了索引(实际上是你的情况下的表格),你是I / O绑定的。第二次运行;由于缓存,它会很快。

加速跳跃的唯一方法是以某种方式将所需的行移到彼此旁边。这对这个查询来说似乎是不合理的。

至于与另一张桌子玩游戏 - 也许吧。 JOIN会显着减少要查看的事件数量吗?然后也许吧。否则,我说“通过增加复杂性,一个非常有效的查询不会变得更快”。