连接 2 个 MySQL 临时表比将临时表与普通表连接并添加 WHERE 子句慢 50 倍?

Pat*_*rry 1 mysql join inner-join temp-tables

我有 2 个组,我试图找到它们的交集(需要 2 列匹配),我发现加入 2 个临时表的性能比仅用一个临时表加入原始表的性能要慢 50 倍。这对我来说毫无意义,所以也许有人可以启发我?

这是我编写 2 个临时表版本的方式:

CREATE TEMPORARY TABLE attendees (
    event_id SMALLINT(5) UNSIGNED,
    person_id INT(10) UNSIGNED NOT NULL,
    KEY(event_id),
    KEY(person_id)
);
INSERT INTO attendees (event_id, person_id) 
    SELECT event_id, person_id
    FROM attendance WHERE year=2013
    GROUP BY event_id, person_id;
CREATE TEMPORARY TABLE invitees (
    event_id SMALLINT(5) UNSIGNED,
    person_id INT(10) UNSIGNED NOT NULL,
    KEY(event_id),
    KEY(person_id)
);
INSERT INTO invitees (event_id, person_id)
    SELECT event_id, person_id
    FROM invitations WHERE year=2013
    GROUP BY event_id, person_id;
SELECT i.event_id, COUNT(DISTINCT i.person_id)
    FROM attendees AS a
    INNER JOIN invitees AS i
        ON a.person_id = i.person_id AND a.event_id = i.event_id
    GROUP BY i.event_id;
Run Code Online (Sandbox Code Playgroud)

这 2 个临时表中的每一个都少于 2,000 行,但这个最终查询在我的笔记本电脑上需要大约 2.5 秒。我不明白这怎么可能。

另一方面,使用以下实现,最终查询只需要 0.05 秒,即使它命中了完整的邀请表(约 100,000 行):

CREATE TEMPORARY TABLE attendees (
    event_id SMALLINT(5) UNSIGNED,
    person_id INT(10) UNSIGNED NOT NULL,
    KEY(event_id),
    KEY(person_id)
);
INSERT INTO attendees (event_id, person_id) 
    SELECT event_id, person_id
    FROM attendance WHERE year=2013
    GROUP BY event_id, person_id;
SELECT i.event_id, COUNT(DISTINCT i.person_id)
    FROM attendees AS a
    INNER JOIN invitations AS i
        ON a.person_id = i.person_id AND a.event_id = i.event_id
    WHERE i.year=2013
    GROUP BY i.event_id;
Run Code Online (Sandbox Code Playgroud)

值得一提的是,原始表(出席和邀请)都有关于 event_id、person_id 和 year 的索引。我首先编写如此复杂代码的原因是,有一些未受邀参加的活动的参加者,我必须计算这些人(参加和受邀,参加未受邀、受邀未参加、均未参加)。

我想我的问题是,这里发生了什么使第二个版本更快?

如果重要,我的服务器版本是 5.5.36 MySQL Community Server(5.6 有几个奇怪的行为破坏了我的网站)。

Bar*_*mar 5

一个连接只能使用一个表的一个索引。而不是单独的索引person_idevent_id,给两个表的复合索引:

CREATE TEMPORARY TABLE attendees (
    event_id SMALLINT(5) UNSIGNED,
    person_id INT(10) UNSIGNED NOT NULL,
    KEY(event_id, person_id)
);

CREATE TEMPORARY TABLE invitees (
    event_id SMALLINT(5) UNSIGNED,
    person_id INT(10) UNSIGNED NOT NULL,
    KEY(event_id, person_id)
);
Run Code Online (Sandbox Code Playgroud)

我怀疑原始attendance表有这样的索引,这使得与该表的连接速度更快。