I have a table like the one below:
id | Follower_id | leader_id | status
----------------------------------------
1 | 2 | 1 | approved
2 | 1 | 2 | approved
3 | 3 | 2 | approved
4 | 1 | 3 | approved
From this table, I want to retrive the Follower_id/leader_id that are mutual.
For examples 2 , 1 are mutual in this table. To achieve this I am using the following sql
SELECT r.follower_id RF
, r.leader_id RL
, l.follower_id LF
, l.leader_id LL
FROM followers r
JOIN followers l
ON l.follower_id = r.leader_id
AND l.leader_id = r.follower_id
WHERE r.status = 'approved'
AND l.status = 'approved';
It returns the expected output, but it is very slow.
How can I optimize this SQL?
Perhaps something simpler might work faster, eg
SELECT follower_id, leader_id
FROM followers a
WHERE follower_id IN (
SELECT follower_id
FROM followers b
WHERE a.leader_id = b.leader_id
AND status = 'approved'
)
AND status = 'approved';
You are joining the whole table with the same table. That make no sense. Try the Inner Join so it will gave you the cut where the Leaders have the same followers or the followers the same leaders. Also you need to use an as
Alias to join your tables.
SELECT *
FROM followers as f
INNER JOIN followers as k on f.follower_id = k.leader_id
WHERE f.follower_id like k.leader_id OR f.follower_id = k.leader_id
Before someone shit storm me, this is an example script which is shown you all entrys of bouth tables. In this case two times the same table.
Better for this is to make 2 Tables. Create an Accounting Table and an Follow Table and join them. should be works fine aswell and faster.
If you want more methods to join Tables take a look here: https://www.w3schools.com/sql/sql_join.asp
Your query produce a duplicate records. This also create some delay for your mysql connection.
To avoid duplication is to solve your problem.
I add my works below,
SELECT r.follower_id RF
, r.leader_id RL
, l.follower_id LF
, l.leader_id LL
FROM sample r
JOIN sample l
ON l.follower_id = r.leader_id
AND l.leader_id = r.follower_id AND r.id < l.id
WHERE r.status = 'approved'
AND l.status = 'approved';
Output:
RF RL LF LL
2 1 1 2
Note: Use your table name
insteed of sample
.
Sometimes EXISTS is very efficient:
select
t.follower_id id1,
t.leader_id id2
from followers t
where
status = 'approved'
and
t.follower_id < t.leader_id
and
exists (
select 1 from followers
where status = 'approved' and follower_id = t.leader_id and leader_id = t.follower_id
)
This query will return each pair only once.
See the demo .
Results:
| id1 | id2 |
| --- | --- |
| 1 | 2 |
First, you can optimize this query with indexes:
SELECT r.follower_id as RF, r.leader_id as RL,
l.follower_id as LF, l.leader_id as LL
FROM followers r JOIN
followers l
ON l.follower_id = r.leader_id AND
l.leader_id = r.follower_id
WHERE r.status = 'approved' AND l.status = 'approved';
The following index should help: followers(follower_id, leader_id, status)
.
I would prefer to write this as exists
. You might also try aggregation:
SELECT f.follower_id, f.leader_id
FROM followers f
WHERE f.status = 'approved'
GROUP BY LEAST(f.follower_id, f.leader_id),
GREATEST(f.follower_id, f.leader_id)
HAVING MIN(f.follower_id) = MIN(f.leader_id);
The last condition guarantees that you have both directions in the data.
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.