【问题标题】:Joining 2 MySQL temporary tables is 50x slower than joining a temporary table with a normal table and adding a WHERE clause?加入 2 个 MySQL 临时表比加入一个普通表和添加 WHERE 子句的临时表慢 50 倍?
【发布时间】:2014-03-19 23:52:06
【问题描述】:

我有 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;

这 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;

不管怎样,原始表(出席和邀请)都有关于 event_id、person_id 和 year 的索引。而我首先编写如此复杂的代码的原因是,有些活动的参与者没有被邀请,我必须计算这些人的维恩图每个部分的计数(参加和邀请,未受邀参加,受邀未参加,均未参加)。

我想我的问题是,这里发生了什么让第二个版本变得如此之快?

以防万一,我的服务器版本是 5.5.36 MySQL Community Server(5.6 有几个奇怪的行为破坏了我的网站)。

【问题讨论】:

  • 为什么要搞乱临时表方法?
  • @MikeBrant 我敢打赌他认为使用较小的桌子会更快:)
  • 如果您有一个更好的建议,它将生成一个事件列表,其中包含 (1) 受邀参加者、(2) 未受邀参加者和 (3) 未受邀参加者的数量不参加,我很想看看。在我在这里引用的查询之后,我对这些表进行了更多查询,它们只是没有任何性能问题。

标签: mysql join inner-join temp-tables


【解决方案1】:

连接只能使用每个表的一个索引。不要在 person_id 和 event_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)
);

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

【讨论】:

  • 为记录,原考勤表没有任何复合索引。但是非常感谢你教我!
猜你喜欢
  • 2012-05-24
  • 1970-01-01
  • 2015-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-13
相关资源
最近更新 更多