简体   繁体   English

如何优化 SQL 查询?

[英]How can I optimize a SQL query?

SELECT *
FROM account a1 
LEFT JOIN account a2 ON a1.group_id>0 AND a2.app_id=0 AND a1.group_id=a2.group_id AND a1.id!=a2.id 
JOIN user_account_ref uar ON uar.account_id=a1.id OR (uar.account_id=a2.id AND uar.role>0) 
WHERE uar.user_id IN ($some_user_ids);

When I replace the where clause by WHERE a1.id IN ($some_account_ids) , the query is fast, but it's very slow for querying in user ids.当我用WHERE a1.id IN ($some_account_ids)替换 where 子句时,查询速度很快,但在用户 ID 中查询却很慢。 I tried to use subqueries but I wasn't able to make it work.我尝试使用子查询,但无法使其工作。

The table schema is like below:表架构如下所示:

---account---
id
app_id
group_id

---user_account_ref---
id
user_id
account_id
role

Some more infos:更多信息:

select * from user_account_ref where user_id IN (xxx)

is fast and has 4 rows in result.速度很快,结果有 4 行。

SELECT * 
FROM account a1 
LEFT JOIN account a2 ON a1.group_id>0 AND a2.app_id=0 AND a1.group_id=a2.group_id AND a1.id!=a2.id

is also fast and has 2000+ rows in result.速度也很快,结果有 2000 多行。

Please try these three indexes and see if they solve your performance issue.请尝试这三个索引,看看它们是否能解决您的性能问题。 (Then look at the explain plan to see which of these indexes don't get used and drop them.) (然后查看解释计划以查看这些索引中的哪些未被使用并删除它们。)

create index idx1 on account (group_id, id, app_id);
create index idx2 on user_account_ref (user_id, account_id);
create index idx3 on user_account_ref (account_id, user_id);

idx1 is for speeding up your account self-join. idx1用于加速您的account自加入。 idx2 and idx3 are two offers to the DBMS to quickly join the user_account_ref table. idx2idx3是 DBMS 快速加入user_account_ref表的两个提议。 Hopefully, the DBMS will pick one of them and get the query execution faster thus.希望 DBMS 会选择其中之一,从而更快地执行查询。

If these indexes don't help, you may try to drop only idx3 first, so as to kind of force idx2 , as it seems that the condition on users greatly decreases the rows to look at and the DBMS may not be waware of this.如果这些索引没有帮助,您可以尝试先只idx3 ,以便强制idx2 ,因为似乎用户的条件大大减少了要查看的行并且 DBMS 可能没有意识到这一点。

At last you may be able to update MySQLs table statistics, so the DBMS knows your tables better.最后,您可以更新 MySQL 的表统计信息,以便 DBMS 更好地了解您的表。 Good luck.祝你好运。

I finally used the UNION query suggested by @Akina.我终于使用了@Akina 建议的 UNION 查询。 And I added a index on group_id which is reminded by @Thorsten Kettner.我在group_id上添加了一个索引,这是@Thorsten Kettner 提醒的。 Thanks to both of you.感谢你们俩。

Here is my new query:这是我的新查询:

SELECT a.id, uar.* 
FROM account a
JOIN user_account_ref uar ON uar.account_id=a.id AND uar.status=0
WHERE uar.user_id IN (xxx)

UNION

SELECT a.id, uar.* 
FROM account a,
(
    SELECT DISTINCT ra.id, ra.group_id
    FROM account ra
    JOIN user_account_ref uar ON ra.id=uar.account_id and ra.app_id=0
    WHERE uar.user_id in (xxx) AND ra.group_id>0
) ra
JOIN user_account_ref uar ON uar.role>0
WHERE a.group_id=ra.group_id AND uar.account_id=ra.id AND uar.user_id IN (xxx);

If this is fast:如果这很快:

SELECT a1.*, a2.* 
FROM account a1 LEFT JOIN
     account a2
    ON a1.group_id > 0 AND 
       a2.app_id = 0 AND
       a1.group_id = a2.group_id AND
       a1.id <> a2.id;

Then use two left join s:然后使用两个left join

    SELECT a1.*, a2.*, COALESCE(uar1.role, uar2.role) as role
    FROM account a1 LEFT JOIN
         account a2
         ON a1.group_id > 0 AND 
            a2.app_id = 0 AND
            a1.group_id = a2.group_id AND
            a1.id <> a2.id LEFT JOIN
         user_account_ref uar1 AND uar2.role > 0
         ON uar1.account_id = a1.id LEFT JOIN
         user_account_ref uar2
         ON uar2.account_id = a2.id AND uar2.role > 0
WHERE uar1.user_id IN ($some_user_ids) OR
      uar2.user_id IN ($some_user_ids) ;

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

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