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