mysql - 非常大的表 JOIN 与 GROUP BY

标签 mysql sql join group-by query-performance

我需要将 2700 万行表和 700 万行表中的信息结合起来并进行一些过滤。

CREATE TABLE event_participation (
    place_id                    int(4),
    person_id                   varchar(12),
    event_id                    varchar(10),
    event_description           varchar(230), 

    .... and more fields about that specific participation

) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE INDEX IDX_1 ON event_participation (place_id);
CREATE INDEX IDX_2 ON event_participation (person_id);
CREATE INDEX IDX_3 ON event_participation (event_id);

CREATE TABLE person (
    person_id                   varchar(12),
    last_name                   varchar(25),
    first_name                  varchar(20),
    middle_name                 varchar(20),

    person_attr1                varchar(20),
    ...
    person_attr50              varchar(20),

) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE INDEX IDX_10 ON person (person_id);
CREATE INDEX IDX_11 ON person (person_attr1);
CREATE INDEX IDX_12 ON person (person_attr2);
...

我对查询中使用的所有属性都有索引。

event_participation表有2700万行,person表有700万行。

我需要运行这样的查询:

SELECT   person.last_name, person.first_name
FROM     event_participation 
    LEFT JOIN person ON event_participation.person_id = person.person_id
WHERE    event_id IN ("event 1", "event 2", "event 3", "event 4",
         "event 5", "event 6", "event 7") AND person.person_attr1 = 'A' AND
         person.person_attr2 = 'B' AND place_id = 90
GROUP BY event_participation.person_id
HAVING   count(event_id) >= 3

解释为:

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: event_participation
         type: ref
possible_keys: person_id,event_id,place_id
          key: place_id
      key_len: 5
          ref: const
         rows: 6437170
        Extra: Using where; Using temporary; Using filesort
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: person
         type: ref
possible_keys: person_id,person_attr1,person_attr2 
          key: person_id
      key_len: 39
          ref: event_participation.person_id
         rows: 1
        Extra: Using where

我正在寻找参加列表中至少 3 项事件并满足其他一些标准的活跃人士。通常我会修复与事件相关的标准,并运行多个仅改变人员属性的查询。

即使对于非常小的子集,此查询也非常慢,因此我寻找替代方法。 我创建一个缓存表:

CREATE TABLE temp_name (
    person_id                   varchar(12),
    PRIMARY KEY (person_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

运行如下查询:

INSERT INTO temp_name (  temp_name ) 
    SELECT   DISTINCT event_participation.person_id
    FROM     event_participation
    WHERE    event_id IN ("event 1", "event 2", "event 3", "event 4",
             "event 5", "event 6", "event 7") AND place_id = 90
    GROUP BY event_participation.person_id
    HAVING   count(event_id) >= 3

然后运行过滤器查询,例如:

SELECT person.last_name, person.first_name
FROM temp_name LEFT JOIN person ON temp_name.person_id = person.person_id
WHERE person.person_attr1 = 'A' AND person.person_attr2 = 'B'

虽然我可以接受最终查询的当前性能,但临时表的创建和管理却让我很痛苦。任何建议都将受到高度赞赏。

最佳答案

你能尝试一下吗:

SELECT   person.last_name, person.first_name
FROM person pers
INNER JOIN
(SELECT person_id, count(*) as count
FROM     event_participation 
WHERE    event_id IN ("event 1", "event 2", "event 3", "event 4",
         "event 5", "event 6", "event 7") AND person.person_attr1 = 'A' AND
         person.person_attr1 = 'B' AND place_id = 90
Group by person_id
) as event_count on event_count.person_id = pers.person_id AND event_count.count>2

更新:我忘记将分组依据添加到内部查询。

关于mysql - 非常大的表 JOIN 与 GROUP BY,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29876271/

相关文章:

mysql - 两个表通过 WHERE 子句条件关联(如果存在或不存在)

两个表的 SQL 查询自连接

sql - View 与索引 View 或物化 View 的区别

MySQL在另一个表中按投票排序

python - Mysql - 如何在比较两个条目时仅识别和选择不同的列?

mysql - 如何搜索关键字在两个表格之间的多个文本中出现的次数

mysql - 从 CentOS 7 或 RHEL 7 中完全删除 MariaDB 或 MySQL

sql - 使用 case 语句对项目进行不同计数

mysql - 如何编写 MySQL 查询

multithreading - 在Perl中,如何等待线程并行结束?