[英]I want to optimize the SQL query because it took too much time
我有这个 SQL 查询的问题。 我想获得每个角色创建的“ops”的数量。
例如 :
| Projects | oprs count (role A) | oprs count (role B) |
|----------|---------------------|-----------------------------|
| Project1 | 100 | 10 |
| Project2 | 10 | 20 |
| Project3 | 80 | 30 |
我已经完成了这个查询,但它很慢,因为“oprs”表很大,你能帮我把它做得更好吗?
EXPLAIN SELECT DISTINCT
pr.id 'project ID',
pr.name 'project',
(SELECT
COUNT(DISTINCT o.id)
FROM
oprs o
LEFT JOIN
accounts ac ON ac.id = o.create_account_id AND NOT(ac.is_deleted)
LEFT JOIN
users u ON u.account_id = ac.id AND NOT(u.is_deleted)
LEFT JOIN
links_users_roles lur ON lur.user_id = u.id AND NOT(lur.is_deleted)
LEFT JOIN
roles r ON r.id = lur.role_id
WHERE
o.project_id = pr.id
AND r.id = 31
)AS 'count oprs created with role A',
(SELECT
COUNT(DISTINCT o.id)
FROM
oprs o
LEFT JOIN
accounts ac ON ac.id = o.create_account_id AND NOT(ac.is_deleted)
LEFT JOIN
users u ON u.account_id = ac.id AND NOT(u.is_deleted)
LEFT JOIN
links_users_roles lur ON lur.user_id = u.id AND NOT(lur.is_deleted)
LEFT JOIN
roles r ON r.id = lur.role_id
WHERE
o.project_id = pr.id
AND r.id = 252
)AS 'count oprs created with role B'
FROM
projets pr
GROUP BY pr.id
这是查询的解释:
先感谢您
我首先将查询编写为单个聚合查询。 我不知道这是否会更快——但可能会。 它绝对更简单:
SELECT pr.id, pr.name,
COUNT(DISTINCT CASE WHEN lur.role_id = 31 THEN o.id END),
COUNT(DISTINCT CASE WHEN lur.role_id = 252 THEN o.id END)
FROM projects pr LEFT JOIN
oprs o
ON o.project_id = pr.id LEFT JOIN
accounts ac
ON ac.id = o.create_account_id AND
NOT(ac.is_deleted) LEFT JOIN
users u
ON u.account_id = ac.id AND
NOT(u.is_deleted) LEFT JOIN
links_users_roles lur
ON lur.user_id = u.id AND
NOT(lur.is_deleted)
GROUP BY pr.id, pr.name;
请注意,“缺少”一张表。 不需要它,因为角色 ID 在links_users_roles
。
接下来,我会质疑是否需要COUNT(DISTINCT)
。 它增加了开销。 如果不是真的有必要,我不会感到惊讶。 这也会加快查询速度。
正如 Gordon Linoff 解释的那样,您可以重构代码以使其更易于阅读。 我想补充一点,您有多种方法可以改进这一点。 首先,您可以实现一个定期加载此查询并保存结果的 cron 作业,因此当需要数据时,只会查询结果,而不是一次又一次地计算冗长的过程。 接下来,您可能希望索引一些字段,例如外键,例如project_id
,这将提高查询的性能。 但是,它会稍微降低保存记录的性能。
从戈登离开的地方开始……
LEFTs
可能是不必要的。
如果NOT(is_deleted)
可以变成is_deleted = 0
或is_deleted IS NULL
,那么我们可以讨论改进一些索引。
对于多对多的表,索引可能可以改进; 见http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table
如果您想进一步讨论,请提供SHOW CREATE TABLE
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.