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. 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.
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.
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. idx2
and idx3
are two offers to the DBMS to quickly join the user_account_ref
table. Hopefully, the DBMS will pick one of them and get the query execution faster thus.
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.
At last you may be able to update MySQLs table statistics, so the DBMS knows your tables better. Good luck.
I finally used the UNION query suggested by @Akina. And I added a index on group_id
which is reminded by @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:
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) ;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.