我对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秒。我确信这根本就是错误的,我只是不知道它是什么。
非常感谢你的帮助!
答案 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';