【问题标题】:MySQL: Optimized join across tablesMySQL:优化的跨表连接
【发布时间】:2013-08-09 23:30:19
【问题描述】:

该查询很慢(大约 1.5 秒)。它应该只返回一个帖子列表

SELECT SQL_NO_CACHE p.id FROM 1_posts p 左连接 1_topics t ON (p.cid = t.cid AND p.container = t.id) 其中 t.cid = 1010699;

解释给出:

+----+-------------+--------+------+--------------- --------+------------+---------+---------------+--- ---+--------------+ |编号 |选择类型 |表|类型 |可能的键 |关键 | key_len |参考 |行 |额外 | +----+-------------+--------+------+--------------- --------+------------+---------+---------------+--- ---+--------------+ | 1 |简单 |吨 |参考 |初级,cid |西德 | 4 |常量 | 216 |使用哪里;使用索引 | | 1 |简单 | p |参考 | PRIMARY,cid,container |集装箱 | 4 | forumdb.t.id | 49 |使用位置 | +----+-------------+--------+------+--------------- --------+------------+---------+---------------+--- ---+--------------+

请注意,SQL_NO_CACHE 仅用于测试目的。

表的部分结构:

1_posts:

mysql> 解释 1_posts; +----------------+------------------------+------+-- ---+---------+----------------+ |领域 |类型 |空 |钥匙 |默认 |额外 | +----------------+------------------------+------+-- ---+---------+----------------+ |西德 | int(20) 无符号 |否 |优先级 | 0 | | |编号 | int(20) 无符号 |否 |优先级 |空 |自动增量 | |集装箱 | int(20) 无符号 |否 |穆尔 | 0 | | mysql>解释1_topics; +-----------------+----------+------+- ----+---------+----------------+ |领域 |类型 |空 |钥匙 |默认 |额外 | +-----------------+----------+------+- ----+---------+----------------+ |西德 | int(10) 无符号 |否 |优先级 | 0 | | |编号 | int(10) 无符号 |否 |优先级 |空 |自动增量 | |集装箱 |整数(20) |否 |穆尔 | 0 | |

表格帖子有数百万条条目,主题约 50 万。

cid 和 id,在两个表上都是主组合键。 cid 表示社区 ID。这些表格承载了许多不同的论坛。

感谢您在加快这方面的速度方面提供的任何帮助。

【问题讨论】:

  • 您确定解释计划来自该查询吗?我不明白为什么会有Using temporary; Using filesort
  • 乍一看,最出乎意料的是查询花了这么长时间。即使表 post 中有 500k 条目,根据查询执行计划,通过使用您的索引,MySQL 只需检查几百行。您是独自在“测试”数据库上 - 还是在实时系统上运行该查询并同时访问您的表?
  • @SylvainLeroux 原因可能是整体服务器负载,但也可能是t.cid = 1010699 是一个边缘情况,它的行数比平均数多得多(这说明显示)。跨度>
  • 已编辑:解释错误。添加了正确的解释输出。
  • 这就是为什么我不明白为什么查询需要这么长时间。也许组合索引是问题?

标签: mysql optimization join query-optimization


【解决方案1】:

当在多个字段上加入(使用 AND)时,在这些字段上建立一个复合索引会有所帮助。

在您的情况下,您可以将帖子中的cid 索引更改为(cid, container),这样mysql 将能够直接查找行(您仍然可以将其用于仅具有cid 条件的查询)。

此外,为了更好的可读性,您可能应该将其设为 INNER JOIN(如 @AndrewK 所述)。

【讨论】:

  • 这个!这解决了问题,现在查询应该是这样。速度极快!
  • 不错的 Vatev。 @Segolene 太好了,您找到了答案(我不应该,但我很惊讶它有这么大的不同!)只是出于好奇,您现在可以运行EXPLAIN SELECT,并报告检查的行数,以比较“之前”和“之后”。
  • 非常感谢大家帮助我解决这个问题。 Sylvain:现在是 EXPLAIN 输出(抱歉格式错误。显然不能使用
     或换行符作为回复)。 |  1 | SIMPLE      | t     | ref  | PRIMARY,cid                 | cid   | 4       | const               |  216 | Using where; Using index | |  1 | SIMPLE      | p     | ref  | PRIMARY,cid,container,cid_2 | cid_2 | 8       | const,ak_slave.t.id |   12 |      |
  • 查询现在几乎是即时的(0.00 秒),顺便说一句。
【解决方案2】:

只需查看您的查询,您就可以简化它。

由于您将集合减少到 t.cid = 1010699 的位置,因此您声明它不能下注为空。所以你可以使用内连接。

SELECT SQL_NO_CACHE p.id 
FROM 1_posts p 
JOIN 1_topics t ON p.container = t.id 
WHERE t.cid = 1010699 AND p.cid = t.cid;

编辑:

正如 Vatev 指出的那样,删除 p.cid = t.cid 确实会改变查询的结果。为了便于阅读,我将其添加回 WHERE 子句中

【讨论】:

  • 关于 JOIN 是 INNER 是正确的,但这对性能没有影响(无论如何,mysql 都会使其成为 INNER JOIN)。删除p.cid = t.cid 会使结果不同。
  • 感谢您的回复,AndrewK。不幸的是,您的查询不会返回与初始查询相同的结果。此外,它对性能没有影响。
  • 安德鲁,性能与初始查询完全相同。
  • 明白。您在 p.container 列上有索引吗?
  • 当然。它是一个常规的 INDEX()。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-01
  • 2019-12-30
  • 2021-12-20
相关资源
最近更新 更多