更快的“IN”陈述的替代品?

时间:2011-03-08 21:01:38

标签: mysql

我对MySQL并不擅长,所以我经常发现自己正在准备有效的次优查询,但我知道必须非常低效。我希望你们能给我一些关于为什么以下查询不能正常工作的指针,以及我应该用什么方法来完成类似的查询。

我有以下表结构:

TABLE Files
files_id => INT(12), PRIMARY, AUTO INCREMENT, NOT NULL
files_name => VARCHAR(255), NOT NULL
(some other fields such as file type etc)

TABLE File_Permissions
perm_id => INT(12), PRIMARY, AUTO INCREMENT, NOT NULL
perm_files_id => INT(12), NOT NULL
perm_users_id => INT(12), NOT NULL

我使用以下SQL提取允许用户查看的文件列表:

SELECT files_name FROM Files WHERE files_id IN 
    (SELECT perm_files_id FROM File_Permissions WHERE perm_users_id = 'xxxxxx');

据我所知,这将遍历Files表中的数千条记录中的每条记录,并且每条记录执行一个子查询,该子查询从File_Permissions表中进行选择以检查用户的ID。

每次查询大约需要2秒。我确信这根本就是错误的,我只是不知道它是什么。

非常感谢你的帮助!

7 个答案:

答案 0 :(得分:2)

对于这种查询,您可以使用JOIN,WHERE ... IN或WHERE EXISTS。如果您有适当的索引,那么使用IN的方法应该没问题。

这样你可以与其他东西进行比较,这里是WHERE EXISTS的一个例子:

SELECT files_name FROM Files
WHERE EXISTS 
(
    SELECT *
    FROM File_Permissions
    WHERE perm_users_id = 'xxxxxx'
    AND files_id = perm_files_id
)

但最重要的是:添加适当的索引!这可能会对性能产生巨大的差异。如果您不确定是否具有正确的索引,请查看以下语句的输出,以查看您拥有的索引以及查询使用的索引:

  • EXPLAIN SELECT ...your query here...
  • SHOW CREATE TABLE Files
  • SHOW CREATE TABLE File_Permissions

如果您仍然不确定,请编辑问题以包含上述每个语句的输出以及这些语句:

  • SELECT COUNT(*) FROM Files
  • SELECT COUNT(*) FROM File_Permissions
  • SELECT COUNT(*) FROM (SELECT ...your query here...) T1

答案 1 :(得分:1)

大多数涉及子查询的IN子句的查询都可以重构为使用连接。在你的情况下:

SELECT files_name 
FROM Files 
JOIN File_Permissions ON files_id = perm_files_id
WHERE perm_users_id = 'xxxxxx';

上面的查询将创建两个表之间的连接结果集,然后按条件过滤。这需要两次传球而不是N + 1.

答案 2 :(得分:0)

您可以按上述方式重新构建查询,但您也可以先尝试在perm_users_id上添加索引。它可能会加快速度。

答案 3 :(得分:0)

您的表需要索引。上面的查询显示您需要以下内容:

Files需求和files_id

上的索引

File_Permissions需求和perm_users_id

上的索引

这将使查询更快。

答案 4 :(得分:0)

我不确定你为什么不只是按照以下方式使用标准联接:

SELECT <required fields> FROM (Files, File_Permissions) WHERE
files_id = perm_files_id AND perm_user_id='xxxxx'

除此之外,你应该确保设置适当的索引等。

隐含联接是邪恶的 - 请参阅下面的评论。 : - )

答案 5 :(得分:0)

SELECT files_name FROM Files LEFT JOIN File_permissions ON files_id = perm_files_id 
AND perm_users_id = 'xxxxx'

同时索引连接列将有助于提高性能。因此,perm_files_id上的索引会提高性能

答案 6 :(得分:0)

两种常见的替代方案是:

SELECT files_name
  FROM Files f
  WHERE EXISTS (
        SELECT *
          FROM File_Permissions
         WHERE f.files_id = perm_files_id
           AND perm_users_id = 'xxxxxx');

SELECT DISTINCT files_name fn
  FROM Files f
  JOIN File_Permissions fp ON f.files_id = fp.perm_files_id
 WHERE perm_users_id = 'xxxxxx';