【问题标题】:mysql explain slow where on left joined tablemysql解释左连接表在哪里慢
【发布时间】:2015-05-23 23:31:29
【问题描述】:

玩着一个mysql,想着以后怎么解决一件事。我想检索由我的朋友(特定用户 ID)发布或在我关注的群组中发布的状态。

CREATE TABLE `status` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `status` text COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_F23501207E3C61F9` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1567559 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

CREATE TABLE `group_status` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `group_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_F23501207E3C61F9` (`group_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

我用 100 万行输入了两个表。

我正在运行的查询:

SELECT s.id, s.status, gs.group_id
FROM status s 
LEFT JOIN group_status gs
ON s.id = gs.id
WHERE 
s.user_id IN (55883,122024,442468,846269,903941,980896,192660,20608,525056,563457)
OR gs.group_id IN (78,79,79,80,80,83,84,85,86,87,88,89,89,91,92,92,94,98)
ORDER BY s.id DESC
LIMIT 15

结果:

问题一:

不应该是额外的角色:“使用索引”而不是“哪里”?

问题二:

为什么响应时间这么慢? 2.3s

在蒂姆回答后编辑:

  1. 我猜在使用 union no 时文件排序行为是正常的?
  2. 为什么在解释的第二行中有'using where'?如果第三个是“使用哪里,使用索引”?
  3. 如果选择返回多少行,您认为这会变慢?

联合选择似乎超级快,但目前只有几行返回每个选择。我将尝试在每个选择中选择更多行。

【问题讨论】:

  • 文件排序可能是status列造成的,定义为Text。
  • s.id = gs.id 让我的大脑开始旋转!为什么你有一个状态的 id 和一个组状态的 id;此外,为什么它们具有相同的语义(因为您正在加入它们)??
  • Rick 你的命名建议是什么?你对这个问题本身有什么要说的吗?

标签: mysql performance sql-execution-plan


【解决方案1】:

如果你在不同的列上有一个“OR”,mysql 可能不使用你的任何索引。

通常我们可以使用“UNION”两个单独的查询来解决问题,每个查询都匹配一个条件。

SELECT id, status, group_id FROM
(
  SELECT s.id, s.status, gs.group_id
  FROM status s 
  LEFT JOIN group_status gs
  ON s.id = gs.id
  WHERE 
  s.user_id IN (55883,122024,442468,846269,903941,980896,192660,20608,525056,563457)
UNION 
  SELECT s.id, s.status, gs.group_id
  FROM status s 
  LEFT JOIN group_status gs
  ON s.id = gs.id
  WHERE 
  gs.group_id IN (78,79,79,80,80,83,84,85,86,87,88,89,89,91,92,92,94,98)
) t
ORDER BY id DESC
LIMIT 15

但是,在您的情况下,如果任一查询返回大量记录,这可能无济于事。

您的状态栏被定义为文本,这可能会导致文件排序。您可以将其检查为 long varchar 以查看文件排序是否正常。或者尝试这样做以避免更糟糕的情况:

SELECT ss.id, group_id, ss.status 
FROM (
SELECT id, group_id FROM
(
  SELECT s.id,  gs.group_id
  FROM status s 
  LEFT JOIN group_status gs
  ON s.id = gs.id
  WHERE 
  s.user_id IN (55883,122024,442468,846269,903941,980896,192660,20608,525056,563457)
UNION 
  SELECT s.id,  gs.group_id
  FROM status s 
  LEFT JOIN group_status gs
  ON s.id = gs.id
  WHERE 
  gs.group_id IN (78,79,79,80,80,83,84,85,86,87,88,89,89,91,92,92,94,98)
) t
ORDER BY id DESC
LIMIT 15
) f
JOIN status ss
ON f.id =ss.id 
ORDER BY ss.id 

【讨论】:

  • 谢谢评论。我用更多细节和问题编辑了我的答案
  • 在大多数情况下,您应该对此类查询使用联合。当您的查询返回非常大的百分比(50% 等)并且您返回的列很多,尤其是 blob 字段时,它可能会变慢。
  • 我将“文本”更改为“varchar (20000)”,但相同。嗯,我不确定您在第二个示例中要达到什么目的?你能透露一下你的想法吗?
  • 第二个样本显着减少了临时结果数据的大小。
  • 我尝试为 s.user_id IN () 添加更大的范围,因此整个第一个子查询返回 25 000 个状态,并且该查询的整体性能约为 150 毫秒(您的第二个查询)。您的意思是通过仅返回子查询中的 id、组 id 来减少?然后只为这 15 个结果再次加入状态表以获取其余信息?
猜你喜欢
  • 2015-11-02
  • 1970-01-01
  • 1970-01-01
  • 2015-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多