【问题标题】:Why does this simple query take forever?为什么这个简单的查询需要永远?
【发布时间】:2012-04-03 19:37:31
【问题描述】:

为什么这个 MySQL 查询在一个有 17k 行的表上需要永远(并且永远不会完成)?

SELECT * FROM files_folders WHERE file IN (SELECT file FROM files_folders WHERE folder = 123);

基本上,一个文件可以位于多个文件夹中(一个物理文件及其副本)。我正在尝试获取文件夹 123 中的所有文件。现在在我的示例中,文件夹 123 中有 2 个文件。ID #4222 和 ID #7121。但是这两个文件可能在其他文件夹以及文件夹 123 中。

我这样做是错误的方式还是我遗漏了什么?

编辑:这是表结构的示例。

+--------------+
| file | folder|
+------+-------+
| 1    | 1     |
| 2    | 1     |
| 1    | 2     |
| 3    | 2     |
| 4    | 3     |
+------+-------+

所以我想选择文件夹 1 中将返回的所有文件(及其副本):

+--------------+
| file | folder|
+------+-------+
| 1    | 1     |
| 2    | 1     |
| 1    | 2     |
+------+-------+

因为文件 1 在文件夹 1 和 2 中。

谢谢。

【问题讨论】:

  • 你有Folder的索引吗?
  • 我错过了什么吗?为什么不只是:SELECT * FROM files_folders WHERE Folder = 123;
  • 为什么不只是SELECT * FROM files_folders WHERE Folder = 123?目前您选择ID where Folder = 123 然后基本上选择* where ID = ID
  • 一个文件可以在多个文件夹中。所以,基本上我想删除文件的每个副本,包括存储在文件夹中的文件,因为文件可以在文件夹中,而所述文件的副本可能在其他地方。

标签: mysql subquery where-in


【解决方案1】:

对于每个文件,MySQL 需要检查ID 是否在子查询返回的结果中。它需要O(N)

N 文件需要这样做。

所以查询的复杂度是O(N^2)。 17k ^ 2 = ~4*10^8 所以大约需要一分钟,也许更短。

为什么您的查询不是

SELECT ID FROM files_folders WHERE Folder = 123

?

【讨论】:

  • 因为一个文件也可以在另一个文件夹中。我将用表结构的示例更新我的帖子。
【解决方案2】:

使用自联接:

SELECT 
  ff.* 
FROM 
  files_folders AS ff
  INNER jOIN files_folders AS f ON f.ID=ff.ID
WHERE
  f.Folder=123
;

【讨论】:

  • 我真正想做的查询是DELETE。 SELECT 工作正常,但只要我将它合并到 DELETE 语句中,它就会再次出现。我已将您查询中的 SELECT ff.* 替换为 DELETE ff。关于为什么需要很长时间的任何想法?谢谢。
  • 使用 DELETE 操作时,自联接在删除的每一行上都会失效,这会抵消性能优势。对于 DELETE,您最好的选择是在一个查询中选择文件夹 ID,然后在生成的 ID 列表上运行 DELETE 查询。这样 IN (...) 的参数是不变的,从而导致快速删除。
  • 我认为我无法在 MySQL IN 函数中传递 ID 列表。我只能做一个子查询。 dev.mysql.com/doc/refman/5.0/en/…
  • 当然可以——我一直都这样做!这是最简单的版本:第一个查询:SELECT CAST(GROUP_CONCAT(DISTINCT file) AS CHAR) FROM files_folders WHERE folder = 123 - 这会返回一个类似1,2,17 的字符串。然后运行"DELETE FROM files_folders WHERE file in (0" + string_from_last_query+")"
  • 嗯,这似乎是用 PHP 之类的脚本语言完成的。我试图用直接的 SQL 来完成这个。
【解决方案3】:

为什么要使用子查询?我认为根本不需要。您可以直接从表格中选择,例如

SELECT * FROM files_folders WHERE Folder = 123

还有第二件事:

“因为一个文件也可以在另一个文件夹中”

使用子查询是什么意思?

【讨论】:

  • 请在下次回答问题时修正语法。如果你的语法不好,就很难理解你想说什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-21
  • 1970-01-01
相关资源
最近更新 更多