简体   繁体   中英

2 very fast and simple queries are terribly slow when merged together

I have these 2 tables. I'm trying to look for the groups the user with id 1 has joined. Here are 10 rows of each table (just to show their layout):

PostTable (57,272 rows, primary key id):

+----+---------+
| id | groupid |
+----+---------+
|  0 |       1 |
|  1 |       1 |
|  3 |       1 |
|  4 |       1 |
|  5 |       1 |
|  9 |       1 |
| 10 |       1 |
| 13 |       1 |
| 15 |       1 |
| 17 |       1 |
+----+---------+

JoinedGroupsTable (258,404 rows, unique index userid,groupid):

+--------+---------+--------+
| id     | groupid | userid |
+--------+---------+--------+
| 258010 |       1 |      1 |
| 258484 |       6 |      1 |
|    172 |       1 |      2 |
|    173 |       2 |      2 |
|    174 |       3 |      2 |
|    175 |       4 |      2 |
|    176 |       5 |      2 |
|    177 |       6 |      2 |
|    178 |       8 |      2 |
|    179 |       9 |      2 |
+--------+---------+--------+

When I try to run this query, it finished in almost 3 seconds which is really slow:

SELECT * FROM posttable p 
WHERE groupid in (SELECT groupid FROM joinedgroupstable WHERE userid=1)
ORDER BY p.ID DESC LIMIt 25;

I've also tried to use INNER JOIN rather than WHERE IN, but ended up with roughly the same result:

SELECT * FROM posttable p 
INNER JOIN joinedgroupstable jg ON userid=1 AND jg.groupid=p.groupid
ORDER BY p.ID DESC LIMIt 25;

Here is the EXPLAIN SELECT for both queries (Same result for both queries):

|| *id* || *select_type* || *table* || *partitions* || *type* || *possible_keys* || *key* || *key_len* || *ref* || *rows* || *filtered* || *Extra* ||
|| 1 || SIMPLE || jg ||  || ref || UserID_GroupID,userid || UserID_GroupID || 4 || const || 2 || 100.00 || Using index; Using temporary; Using filesort ||
|| 1 || SIMPLE || p ||  || ref || groupid || groupid || 4 || thyra.jg.groupid || 60 || 100.00 ||  ||

The thing is that running each query on its own is super fast:

SELECT * FROM posttable p ORDER BY p.ID DESC LIMIt 25;

SELECT * FROM joinedgroupstable WHERE userid=1

What could be wrong considering each query runs super fast on its own but slow when merged?

If your question is simplified and your PostTable contains more columns than you showed us, your ORDER BY ... LIMIT ... clause is causing a lot of wasted sorting.

You can do a so-called "deferred join." First get the appropriate id values, then use them to retrieve the rows.

select p.* 
  from posttable p
  join (
       select a.id
       from posttable a
       join joinedgroupstable g on a.groupid = g.groupid
      where g.userid = 1
      order by a.id desc
      limit 25
     ) sel on sel.id = p.id
order by p.id desc
limit 25;

This confines the expensive ORDER BY ... LIMIT ... operation to just the id column, then uses the chosen id values to hit your main table only 25 times.

I would use EXISTS instead that could be also perform better :

select p.*
from posttable p 
where exists (select 1 
              from joinedgroupstable jg
              where jg.groupid = p.groupid and jg.userid = 1
              )
order by p.id desc
limit 25;

To speed up the first query add the following indexes:

create index ix1 on joinedgroupstable (userid, groupid);

create index ix2 on PostTable (id);

The second query looks wrong to me.

Different answer:

create index ix10 on joinedgroupstable (userid);

create index ix11 on posttable (groupid);

select p.* 
  from posttable p
  join joinedgroupstable g on p.groupid = g.groupid
  where g.userid = 1
  order by p.id desc
  limit 25;

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.

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