【问题标题】:mysql group by joined column too slowmysql 按加入列分组太慢
【发布时间】:2019-12-02 12:44:15
【问题描述】:

我有两张桌子eventsevent_params

第一个表用这些列存储事件

events | CREATE TABLE `events` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `project` varchar(24) NOT NULL,
  `event` varchar(24) NOT NULL,
  `date` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `project` (`project`,`event`)
) ENGINE=InnoDB AUTO_INCREMENT=2915335 DEFAULT CHARSET=latin1

第二个用这些列存储每个事件的参数

event_params | CREATE TABLE `event_params` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `event_id` int(10) unsigned NOT NULL,
  `name` varchar(24) NOT NULL,
  `value` varchar(524) CHARACTER SET utf8 NOT NULL,
  PRIMARY KEY (`id`),
  KEY `name` (`name`),
  KEY `event_id` (`event_id`),
  KEY `value` (`value`),
) ENGINE=InnoDB AUTO_INCREMENT=20789391 DEFAULT CHARSET=latin1

现在我想获取在指定参数上具有不同值的事件的计数

我为campaign 参数编写了此查询,但这太慢了(15 秒响应)

SELECT
    event_params.value as campaign,
    count(*) as count
FROM `events`
    left join event_params on event_params.event_id = events.id
                          and event_params.name = 'campaign'
WHERE events.project = 'foo'
GROUP by event_params.value

这是EXPLAIN的查询结果:

+----+-------------+--------------+------------+------+---------------------+----------+---------+------------------+------+----------+----------------------------------------------+
| id | select_type | table        | partitions | type | possible_keys       | key      | key_len | ref              | rows | filtered | Extra                                        |
+----+-------------+--------------+------------+------+---------------------+----------+---------+------------------+------+----------+----------------------------------------------+
|  1 | SIMPLE      | events       | NULL       | ref  | project             | project  | 26      | const            |    1 |   100.00 | Using index; Using temporary; Using filesort |
|  1 | SIMPLE      | event_params | NULL       | ref  | name,event_id,value | event_id | 4       | events.events.id |    4 |   100.00 | Using where                                  |
+----+-------------+--------------+------------+------+---------------------+----------+---------+------------------+------+----------+----------------------------------------------+

我可以加快这个查询吗?

【问题讨论】:

  • 请使用SHOW CREATE TABLE table 结构为查询中涉及的每个表和EXPLAIN query 输出更新问题,我们需要它来解决性能问题..
  • 你能发个小提琴吗?我看不出一个仅包含 4 行的数据集是如何花费任何时间的!?!
  • @Strawberry 不,我不太了解解释查询,但数据集有 300 万个事件和 1000 万个 event_params
  • 欢迎来到 EAV 模式模式的低效率之一。
  • 桌子有多大? 'foo' 的百分比是多少? “广告系列”占多少百分比?

标签: mysql performance join group-by entity-attribute-value


【解决方案1】:

您可以尝试在event_params 表上添加以下索引,这可能会加快连接速度:

CREATE INDEX idx1 ON event_params (event_id, name, value);

聚合步骤可能无法进行太多优化,因为COUNT 操作涉及对每条记录进行计数。

【讨论】:

  • 我已经添加了这个索引但是查询执行还是太慢了
  • 接下来该学习如何使用EXPLAIN并检查查询计划了。
  • 可能组合 (event_id, name) 是独一无二的。在这种情况下,使PRIMARY KEY,折腾id
【解决方案2】:

将“campaign value”移动到主表中,长度适合VARCHAR,然后

SELECT
    campaign,
    count(*) as count
FROM `events`
WHERE project = 'foo'
GROUP by campaign

还有

INDEX(project, campaign)

尝试使用 EAV 时的一些建议:将“重要”值移动到主表中;在另一个表中只保留很少使用或很少设置的“值”。另外(假设没有重复),有

PRIMARY KEY(event_id, name)

更多讨论:http://mysql.rjweb.org/doc.php/eav

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-04
    • 1970-01-01
    相关资源
    最近更新 更多