【问题标题】:MySql Join Type Weirdness (using "ALL" instead of "eq_ref")MySql 连接类型怪异(使用“ALL”而不是“eq_ref”)
【发布时间】:2016-11-23 01:27:02
【问题描述】:

我正在为一些数据构建一个扁平化查询,我得到了这个外键,导致查询突然从 0.031 秒运行到 2.460 秒运行。我分析了查询,连接是作为ALL 连接完成的,带有额外的Using where; Using join buffer (Block Nested Loop),而不是eq_ref 连接。

为了弄清楚发生了什么,我复制了两张表并将它们精简到最低限度。表定义是:

CREATE TABLE `zz_submission` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `rcId` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_rcId` (`rcId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `zz_rc` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

zz_rc 有 5 行名称。 zz_submission 有 5 行具有来自 RC 的有效 id。

当我运行这个查询时,表r 的“类型”是all

explain SELECT
    s.ID,
    r.name
FROM zz_submission s
    LEFT JOIN zz_rc r ON s.rcId = r.id
;

当我运行这个查询时,表r 的“类型”是eq_ref

explain SELECT
    s.ID,
    r.id
FROM zz_submission s
    LEFT JOIN zz_rc r ON s.rcId = r.id
;

为什么在连接表中选择 ID 与名称列会影响连接类型?我在原始查询中对此进行了测试,它再次切换回以 0.031 秒运行。

如何使查询在此处使用 eq_ref 连接?

【问题讨论】:

  • 您没有显示解释输出,总行数。您的问题缺乏细节
  • 你把它们剥离得太多了。对于 5 行,扫描表比使用任何索引都快。
  • 对不起,我添加了解释输出。

标签: mysql join optimization


【解决方案1】:

您的查询似乎读取了整个 s 表,然后读取了大部分或全部 r 表,对吗?

Using join buffer 表示它将所需数据从r 加载到缓冲区中。这可以通过快速扫描索引(在您的情况下为 PK)来完成。然后,可以在 RAM 中进行查找,而无需进一步点击r。 -- 这解释了ALL 而不是eq_ref

第一个SELECT 需要idname;第二个只需要id。根据数据类型(我或优化器不知道 VARCHAR 的庞大性),人们会猜测 [id,name] 会比 [id] 大得多。

“连接缓冲区”的大小有限 -- SHOW VARIABLES LIKE 'join_buffer_size';。所以它可能包含所有 [id] 但不足以容纳 [id,name]。

names 真的有将近 255 个字符吗?你的例子可能是一个很好的例子,为什么 255 不应该是每个人的默认值。

eq_ref 意味着它将在r 中进行相当有效的查找。但这可能比Using join buffer 慢。

Block Nested Loop 大致意思是:循环通过s,到达r 的每一行。

每个连接都可能分配一个“连接缓冲区”,因此不要使其大于 RAM 的 1%。

【讨论】:

  • 正确。 S 是我的主表,我从中获取所有行。我从 R 加入 FK 以获得状态名称。我不明白为什么连接类型和执行时间仅根据我从连接表中选择的列而变化如此之大。
  • 见第二段“为什么是 ALL,而不是 eq_ref”。
猜你喜欢
  • 2016-04-18
  • 2011-05-29
  • 1970-01-01
  • 2010-09-22
  • 2015-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-09
相关资源
最近更新 更多