Mysql “更快速的替代方案”;在;声明?

Mysql “更快速的替代方案”;在;声明?,mysql,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 typ

我对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秒钟。我确信这是根本错误的,我只是不知道是什么


非常感谢你的帮助

您可以如上所述重新构造查询,但也可以尝试先在perm_users_id上放置索引。它可能会大大加快速度。

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

文件
需求和
文件索引\u id

File\u权限
perm\u用户id上的需求和索引

这将使查询速度大大加快。

我不确定您为什么不使用标准联接,如下所示:

SELECT <required fields> FROM (Files, File_Permissions) WHERE
files_id = perm_files_id AND perm_user_id='xxxxx'
从(文件、文件权限)中选择,其中
files\u id=perm\u files\u id和perm\u user\u id='xxxxx'
除此之外,您应该确保设置了适当的索引,等等

隐式连接是邪恶的-请参阅下面的注释。:-)

试试看

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

此外,为连接的列编制索引将有助于提高性能。因此,在perm_files_id上建立索引将提高性能

对于这种查询,您可以使用连接,其中。。。在,或存在的地方。假设您有适当的索引,那么使用类似于您所发布的方法应该可以

为了便于和其他东西进行比较,这里有一个例子说明存在的地方:

SELECT files_name FROM Files
WHERE EXISTS 
(
    SELECT *
    FROM File_Permissions
    WHERE perm_users_id = 'xxxxxx'
    AND files_id = perm_files_id
)
但最重要的是:添加适当的索引!这会对性能产生巨大的影响。如果您不确定是否有正确的索引,请查看以下语句的输出,查看您有哪些索引以及查询正在使用哪些索引:

  • EXPLAIN在此处选择您的查询…
  • 显示创建表文件
  • 显示创建表文件\u权限
如果您仍然不确定,请编辑问题以包括上述每个陈述的输出以及以下内容:

  • 从文件中选择COUNT(*)
  • 从文件权限中选择COUNT(*)
  • SELECT COUNT(*)FROM(在此处选择您的查询…)T1

两种常见的替代方案是:

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


大多数涉及子查询IN子句的查询都可以重构为使用联接。就你而言:

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

上面的查询将创建两个表之间联接的结果集,然后根据条件进行筛选。这需要两次通过,而不是N+1。

否。编码器不好。这是旧的连接方式;它效率低下,不应该用在任何支持新联接语法的SQL RDBMS中,当然也不应该用在旨在教育的答案中。@KeithS我已经消除了我的错误。我必须承认,如果这是问题的话,我不知道这些天隐式连接被认为是邪恶的。(我假设SQL解释器刚刚将此语法转换为“正常”左连接。)请随意启发我,然后我将删除此答案;例如,SQLServer将为类似这样的简单操作生成相同的执行计划。然而,一旦你学会了“ANSI Join”语法,它就更容易理解,也更难搞错,仅出于这些原因,我能接触到的几乎每一本SQL书籍和博客都推荐使用它,而不是旧式的Join。此外,当OP从MySQL转移到MS SQL Server或Oracle时,他会发现这两个版本的最新版本都不再支持旧的连接语法。@KeithS感谢您提供的信息。老实说,我会把这个问题原封不动地保留下来,因为我想说,你提供的建议证明了它的存在是合理的。希望没有其他人投反对票。:-)您应该添加关于现有(如果有的话)索引的信息没有现有索引,这可能会在任何地方重复文件名。正因为如此,使用
连接
而不是
中的
,显然会使查询速度加快100倍(1.5s->.015s)。这是我不知道的事情。干杯@马塞洛州-有效点;如果文件中有多个权限\u应用于每个文件的权限,此联接将创建重复的条目,每个条目对应于授予同一文件的权限。在此特定查询中,您可以使用SELECT DISTINCT为每个文件只返回一行;但是,如果您开始在列列表中包含来自File_权限的信息,重复的文件名将返回,因为每行的数据作为一个单元都是唯一的。+1感谢您提供有关索引的信息,在添加正确的索引后,我以前使用in的查询从1.5s变为.09s(快15倍!)
SELECT files_name 
FROM Files 
JOIN File_Permissions ON files_id = perm_files_id
WHERE perm_users_id = 'xxxxxx';