繁体   English   中英

提高 SQL 查询性能的最佳方法是什么?

[英]What is the best way to improve the performance of my SQL query?

目前我有以下两个表(这里显示有点简化):

用户:(userId,用户名,email,名称)权限:(id,userId,权限)

权限字段可能包含例如 canRead、canWrite、canDelete 等内容。每个用户可以拥有任意数量的权限。

我现在编写了一个查询来显示所有用户并获取每个用户的权限作为额外的 boolean 列。 例如,对于在系统中注册的两个用户,SQL 脚本的结果应该是这样的:

userId: 1, username: "testuser", email: "test@test.com", name: "testname", canRead: 1, canWrite: 0, canDelete: 0
userId: 2, username: "anotheruser", email: "second@test.com", name: "anothername", canRead: 1, canWrite: 1, canDelete: 1

我当前的查询如下所示:

SELECT users.userId, users.username, users.email, users.name,
CASE WHEN(
  SELECT DISTINCT permissions.permission
  FROM permissions
  WHERE permissions.permission = 'canRead' AND users.userId = permissions.userId
) IS NULL THEN 0 ELSE 1 END AS 'canRead',
CASE WHEN(
  SELECT DISTINCT permissions.permission
  FROM permissions
  WHERE permissions.permission = 'canWrite' AND users.userId = permissions.userId
) IS NULL THEN 0 ELSE 1 END AS 'canWrite',
CASE WHEN(
  SELECT DISTINCT permissions.permission
  FROM permissions
  WHERE permissions.permission = 'canDelete' AND users.userId = permissions.userId
) IS NULL THEN 0 ELSE 1 END AS 'canDelete',
FROM users
LEFT JOIN permissions
ON permissions.userId = users.userId
GROUP BY users.userId

我添加的权限越多,查询就越慢。 如何以更简化且特别高效的方式编写此查询?

您可以通过单个 JOIN 和一些数据操作来完成此操作:

SELECT 
    users.userId, users.username, users.email, users.name,
    COUNT(IF(permissions.permission = 'canRead', 1, null)) > 0 'canRead',
    COUNT(IF(permissions.permission = 'canWrite', 1, null)) > 0 'canWrite',
    COUNT(IF(permissions.permission = 'canDelete', 1, null)) > 0 'canDelete'
FROM users
LEFT JOIN permissions ON users.userId = permissions.userId
GROUP BY users.userId, users.username, users.email, users.name;

MySQL JOIN 小提琴

简化它。 麦克斯他们。

SELECT u.userId, u.username, u.email, u.name
, MAX(CASE WHEN p.permission = 'canRead' THEN 1 ELSE 0 END) AS canRead
, MAX(CASE WHEN p.permission = 'canWrite' THEN 1 ELSE 0 END) AS canWrite
, MAX(CASE WHEN p.permission = 'canDelete' THEN 1 ELSE 0 END) AS canDelete
FROM users u
LEFT JOIN permissions p
  ON p.userId = u.userId
GROUP BY u.userId, u.username, u.email, u.name;
  • 删除它(它似乎没有任何目的,但需要时间):

     LEFT JOIN permissions ON permissions.userId = users.userId
  • 此权限索引: INDEX(userId, permission)可能会有所帮助。 (请参阅下面的警告。)

  • 没有LEFT JOINGROUP BY就变得不必要了; 摆脱它。

  • 切换到EXISTS 例如

     ( SELECT DISTINCT permissions.permission FROM permissions WHERE permissions.permission = 'canRead' AND users.userId = permissions.userId ) IS NULL THEN 0 ELSE 1 END AS 'canRead',

-->

    EXISTS ( SELECT 1 FROM permissions
            WHERE  permissions.permission = 'canRead'
              AND  users.userId = permissions.userId 
    ) AS 'canRead',

Exists() 可能比其他答案更快,因为EXISTS是“半连接”,这意味着它在发现匹配行时停止。 其他人必须检查所有相关行,这需要更长的时间。

  • “用户:(userId,用户名,email,名称)权限:(id,userId,permission)”意味着您在users上有两个唯一键? 需要id吗? 如果您摆脱id并使userId成为PRIMARY KEY ,那么我上面的索引建议就变得多余了。

  • 如需进一步讨论,请为每个表提供SHOW CREATE TABLE

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM