限制按列分组

Posted

技术标签:

【中文标题】限制按列分组【英文标题】:restriction on group by column 【发布时间】:2016-11-07 21:39:40 【问题描述】:

我在 mysql 中有以下表格和查询:

CREATE TABLE IF NOT EXISTS `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,
  `data` json,
  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;

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;

当前的查询通过“使用索引进行分组”有效地运行。是否可以对其进行修改以将其分组的 pv_names 集限制为 matching_pv_names 表中的 pv_names 集,并且仍然保留“使用索引进行分组”优化?例如,以下查询不再使用此优化:

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

有没有别的写法?

【问题讨论】:

【参考方案1】:

您的第一个 SQL 可以从 GROUP BY 优化中受益,因为它只使用一个表,并且您用于 GROUP BY 的列上有索引,并且您使用的唯一聚合函数是 MAX()。并且在 WHERE 子句中使用常量。

在查询中添加另一个表后,GROUP BY optimization 将无法应用。

【讨论】:

我认为你是对的。我希望有办法解决,因为我可以在查询中添加 WHERE events.pv_name LIKE 并保留优化。 您不应该争取获得特定的优化,而应该争取“最佳”优化。 我相信这是最好的优化,无论是在文档中还是在对我的数据集进行测试时。【参考方案2】:

您询问了具体的优化问题,但真正的问题不是关于效率吗?

看看效果如何:

SELECT  e.pv_name, MAX(e.time_stamp) AS time_stamp
    FROM  events AS e
    JOIN  matching_pv_names AS m USING(pv_name)
    WHERE  e.time_stamp <= @time_stamp_in
    GROUP BY  e.pv_name;

一种比较两个查询效率的方法,即使表很小,也是

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

从历史上看,这个结构的优化很差:IN ( SELECT ... )。 (我不知道在您的版本中它是否对您的查询效果不佳。)

【讨论】:

以上是关于限制按列分组的主要内容,如果未能解决你的问题,请参考以下文章

在 xsl:fo 表中按列行值分组

ListView 按列值分组

计算按列分组的模式

按列值分组的列值更新mysql排名

按列对分组数据帧进行采样

熊猫数据框按列位置分组