How to speed up MySQL table join

时间:2016-10-20 18:56:16

标签: mysql performance left-join

I have two tables, one containing some user details, another containing a running log of user requests including timestamp and location columns. They both share a common user_id column.

I'm basically trying to retrieve a list of all user information with their latest location and timestamp included.

This is how I'm currently achieving this, and it's definitely working - however this query in particular is taking over 2 seconds on average.

SELECT u.*, o.time, o.location 
FROM users u 
LEFT JOIN 
    (SELECT DISTINCT user_id, 
            time, 
            location 
     FROM onlineStatus o 
     WHERE time = (select MAX(time) 
                   FROM onlineStatus 
                   WHERE user_id = o.user_id)
    ) AS o 
 ON o.user_id = u.user_id 
WHERE user_type = "1" 
AND user_enabled = "0" 
AND user_realm = ? 
GROUP BY u.user_id

This is frustrating when I need to run multiple of these iterating over different user_type's. I'm not entirely sure how to speed this up, any help would be appreciated. Thanks.

2 个答案:

答案 0 :(得分:1)

You can rewrite that query and make it faster depending on the size of both tables, but you should introduce new table and update it when you insert into the onlineStatus table and then join that table with the user table:

CREATE TABLE onlineStatusLast ( user_id int unsigned not null primary key , last_time timestamp , location varchar(100) , KEY last_time(last_time) );

INSERT INTO onlineStatusLast (user_id, location, last_time) 
values (1, 'Canada', now()) 
on duplicate key update last_time=NOW(), locaton='Canada';

Populate table with

INSERT INTO onlineStatusLast (user_id, last_time) 
select user_id, MAX(time) FROM onlineStatus group by user_id

Your query would become this:

SELECT u.*, o.last_time, o.location 
FROM users u 
LEFT JOIN onlineStatusLast o
AS o ON o.user_id = u.user_id 
WHERE user_type = "1" 
AND user_enabled = "0" 
AND user_realm = ? 

答案 1 :(得分:0)

Create index for

users(user_id)
location(user_id, time)

Query:

SELECT u.*, l1.time, l1.location 
FROM users u 
INNER JOIN location l1
  ON u.user_id = l1.user_id
LEFT  JOIN location l2
  ON l1.user_id = l2.user_id
 AND l1.time < l2.time
WHERE l2.time IS NULL   -- this select the only the LAST time by user
  AND user_type = "1" 
  AND user_enabled = "0" 
  AND user_realm = ?