3

在 MySQL 5.1.34 服务器上,我遇到了以下令人困惑的情况:

mysql> explain select * FROM master.ObjectValue WHERE id IN ( SELECT id FROM backup.ObjectValue ) AND timestamp < '2008-04-26 11:21:59';
+----+--------------------+-------------+-----------------+-------------------------------------------------------------+------------------------------------+---------+------+--------+-------------+
| id | select_type        | table       | type            | possible_keys                                               | key                                | key_len | ref  | rows   | Extra       |
+----+--------------------+-------------+-----------------+-------------------------------------------------------------+------------------------------------+---------+------+--------+-------------+
|  1 | PRIMARY            | ObjectValue | range           | IX_ObjectValue_Timestamp,IX_ObjectValue_Timestamp_EventName | IX_ObjectValue_Timestamp_EventName | 9       | NULL | 541944 | Using where | 
|  2 | DEPENDENT SUBQUERY | ObjectValue | unique_subquery | PRIMARY                                                     | PRIMARY                            | 4       | func |      1 | Using index | 
+----+--------------------+-------------+-----------------+-------------------------------------------------------------+------------------------------------+---------+------+--------+-------------+
2 rows in set (0.00 sec)

mysql> select * FROM master.ObjectValue WHERE id IN ( SELECT id FROM backup.ObjectValue ) AND timestamp < '2008-04-26 11:21:59';
Empty set (2 min 48.79 sec)

mysql> select count(*) FROM master.ObjectValue;
+----------+
| count(*) |
+----------+
| 35928440 |
+----------+
1 row in set (2 min 18.96 sec)
  • 访问所有记录只需要 2 分钟,怎么可能需要 3 分钟检查 500000 条记录?
  • 如何将单独数据库上的子查询分类为依赖?
  • 我能做些什么来加快这个查询?

更新:

需要很长时间的实际查询是 DELETE,但您无法对此进行解释;DELETE 是我使用子选择的原因。我现在已经阅读了文档并发现了语法“DELETE FROM t USING ...”重写查询:

DELETE FROM master.ObjectValue 
WHERE timestamp < '2008-06-26 11:21:59' 
AND id IN ( SELECT id FROM backup.ObjectValue ) ;

进入:

DELETE FROM m 
USING master.ObjectValue m INNER JOIN backup.ObjectValue b ON m.id = b.id 
WHERE m.timestamp < '2008-04-26 11:21:59';

将空备份的时间从几分钟减少到 0.01 秒。ObjectValue。

谢谢大家的好建议。

4

4 回答 4

5

依赖子查询将您的外部查询减慢到爬行(我想您知道这意味着它在正在查看的数据集中找到的每行运行一次)。

您不需要那里的子查询,不使用子查询会大大加快您的查询速度:

SELECT m.*
FROM master.ObjectValue m
JOIN backup.ObjectValue USING (id)
WHERE m.timestamp < '2008-06-26 11:21:59'

MySQL 经常将子查询视为依赖,即使它们不是。我从来没有真正理解过它的确切原因——也许仅仅是因为查询优化器未能将其识别为独立的。我从不费心查看更多细节,因为在这些情况下,您几乎总是可以将其移至FROM修复它的子句。

例如:

DELETE FROM m WHERE m.rid IN (SELECT id FROM r WHERE r.xid = 10)
// vs
DELETE m FROM m WHERE m.rid IN (SELECT id FROM r WHERE r.xid = 10)

前者会产生一个依赖子查询,并且可能非常慢。后者将告诉优化器隔离子查询,从而避免表扫描并使查询运行得更快。

于 2012-04-26T09:56:20.607 回答
3

访问所有记录只需要 2 分钟,怎么可能需要 3 分钟检查 500000 条记录?

COUNT(*)COUNT(1)在 MySQL中总是转换为。所以它甚至不必输入每条记录,而且,我想它使用内存索引来加快速度。在长时间运行的查询中,您使用范围 ( <) 和IN运算符,因此对于它访问的每条记录,它必须做额外的工作,特别是因为它识别子查询是依赖的。

如何将单独数据库上的子查询分类为依赖?

好吧,它是否在单独的数据库中并不重要。如果子查询依赖于外部查询中的值,则子查询是依赖的,在你的情况下你仍然可以这样做......但你不这样做,所以它被归类为依赖子查询确实很奇怪。也许这只是 MySQL 中的一个错误,这就是为什么它需要这么长时间 - 它为外部查询选择的每条记录执行内部查询。

我能做些什么来加快这个查询?

首先,尝试使用JOIN

SELECT master.*
FROM master.ObjectValue master
JOIN backup.ObjectValue backup
  ON master.id = backup.id
  AND master.timestamp < '2008-04-26 11:21:59';
于 2012-04-26T09:56:32.267 回答
3

请注意它是如何说子查询只有 1 行的?显然不止1行。这表明 mysql 一次只加载 1 行。mysql 可能试图做的是“优化”子查询,以便它只加载子查询中也存在于主查询中的记录,一个依赖子查询。这就是连接的工作方式,但是您对查询的表述方式迫使您逆转优化的连接逻辑。

您已经告诉 mysql 加载备份表(子查询),然后将其与主表“timestamp < '2008-04-26 11:21:59'”的过滤结果进行匹配。Mysql 确定加载整个备份表可能不是一个好主意。所以mysql决定使用master的过滤结果来过滤backup查询,但是尝试过滤subquery时master查询还没有完成。因此,它需要在从主查询加载每条记录时进行检查。因此,您的依赖子查询。

正如其他人提到的,使用连接,这是正确的方法。加入人群。

于 2012-04-26T10:26:32.713 回答
0

真正的答案是,不要使用 MySQL,它的优化器是垃圾。切换到 Postgres,从长远来看,它将为您节省时间。

对于每个说“使用 JOIN”的人来说,这只是 MySQL 人群的无稽之谈,他们 10 年来一直拒绝修复这个可怕的错误。

于 2012-09-06T09:00:43.163 回答