简体   繁体   中英

Avoid MySQL 'using temporary' in certain cases

I have two tables, users and followers :

Table users :

id          INT, PRIMARY_KEY
name        VARCHAR
joined      INT

This table is indexed on id and joined .

Table 'followers':

user        INT
follows     INT 

This table is indexed on users and follows .

This query finds the names of all users followed by a particular user who joined after a particular time. The results need to be in reverse chronological order.

SELECT u.name 
FROM users u, followers f
WHERE f.user = X
AND f.follows = u.id
AND u.joined > 1234
ORDER BY u.joined DESC

Now, when user X has a large number of followers, EXPLAIN gives the following:

id      key             extra
-----------------------------------
u       joined          Using where
f       follows         Using index

So far so good. (The 'using where' is due to some other clauses I've removed for brevity).

But, when user X has a small number of followers, this happens:

id      key             extra
-----------------------------------
f       follows         Using temporary, using filesort
u       joined          Using where

If I omit the ORDER BY , I get:

id      key             extra
-----------------------------------
f       follows         
u       joined          Using where

The MySQL optimiser seems to be inspecting the number of rows it has to deal with, and if its small, doing the followers table first. It seems to ignore the ORDER BY in its optimisation steps, resulting in a slower query due to the temporary table.

So (finally), my question is: is it possible to force the order in which MySQL performs table searches, and in the likely event this isn't possible, is there another way to get rid of using temporary ?

MySQL DOES offer a clause "STRAIGHT_JOIN" which tells it to do the join between tables in the order you've provided. Since you are looking for a single specific "Follower User" put the follower table up front and join from that... Try something like

SELECT STRAIGHT_JOIN
      u.name
  from
     followers f
        join Users u
           on f.follows = u.id
          and u.joined > 1234
  where
     f.user = X
  order by 
     u.joined DESC

This should FORCE Starting with the "Followers" table, specific for user ID = X, then join out to the users table as SECONDARY based on the rows returned from f.user = X. Make sure your Followers table has an index where "user" is in the first position (in case your index on both columns was (follows, user), it SHOULD be (user, follows). The smallest granularity on your query basis is the one person inquiring about... that comes in FIRST.

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