Reputation: 5556
I have quite big table with millions of records. The query below executes in just 0.2s, which is fine.
SELECT ch1.*
FROM citizens_history ch1
WHERE ch1.update_id_to = (
SELECT MAX( ch2.update_id_to )
FROM citizens_history ch2
WHERE ch2.id = ch1.id
)
ORDER BY ch1.experience DESC
LIMIT 100
However, when I tried to add INNER JOIN, like this
SELECT ch1.*, upd.*
FROM citizens_history ch1
INNER JOIN updates upd ON upd.id = ch1.update_id_to
WHERE ch1.update_id_to = (
SELECT MAX( ch2.update_id_to )
FROM citizens_history ch2
WHERE ch2.id = ch1.id
)
ORDER BY ch1.experience DESC
LIMIT 100
It takes forever to execute. In first situation I think MySQL is doing this:
In second situation, I assume this happens:
Do you have any advices how can I optimize this?
Edit: EXPLAIN for fast and slow query:
+----+--------------------+-------+-------+---------------+------------+---------+--------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+-------+---------------+------------+---------+--------------+------+-------------+
| 1 | PRIMARY | ch1 | index | NULL | experience | 3 | NULL | 100 | Using where |
| 2 | DEPENDENT SUBQUERY | ch2 | ref | id | id | 3 | db.ch1.id | 1 | Using index |
+----+--------------------+-------+-------+---------------+------------+---------+--------------+------+-------------+
+----+--------------------+-------+-------+-------------------------------------+----------+---------+--------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+-------+-------------------------------------+----------+---------+--------------+------+----------------------------------------------+
| 1 | PRIMARY | upd | index | PRIMARY | datetime | 5 | NULL | 389 | Using index; Using temporary; Using filesort |
| 1 | PRIMARY | ch1 | ref | PRIMARY,update_id_to,update_id_to_2 | PRIMARY | 4 | db.upd.id | 112 | Using where |
| 2 | DEPENDENT SUBQUERY | ch2 | ref | id | id | 3 | db.ch1.id | 1 | Using index |
+----+--------------------+-------+-------+-------------------------------------+----------+---------+--------------+------+----------------------------------------------+
Upvotes: 2
Views: 109
Reputation: 9724
You can try:
SELECT ch1.*
FROM citizens_history ch1
LEFT JOIN citizens_history ch2
ON ch2.id = ch1.id
AND ch1.max_update_id_to > ch2.update_id_to
WHERE ch1.max_update_id_to is null
ORDER BY ch1.experience DESC
LIMIT 100
Upvotes: 0
Reputation: 21513
Performing the first stage as a JOIN to a sub query, and then joining on the updates table:-
SELECT ch1.*, upd.*
FROM citizens_history ch1
INNER JOIN
(
SELECT id, MAX( update_id_to ) AS max_update_id_to
FROM citizens_history
GROUP BY id
) ch2 ON ch1.id = ch2.id AND ch1.update_id_to = ch2.max_update_id_to
INNER JOIN updates upd ON upd.id = ch1.update_id_to
ORDER BY ch1.experience DESC
LIMIT 100
Upvotes: 0
Reputation: 33935
Rewrite the first query as follows, and then modify as required...
SELECT ch1.*
FROM citizens_history ch1
JOIN
( SELECT id
, MAX(update_id_to) max_update_id_to
FROM citizens_history
GROUP
BY id
) ch2
ON ch2.id = ch1.id
AND ch2.max_update_id_to = ch1.update_id_to
ORDER
BY ch1.experience DESC
LIMIT 100
If you're still struggling (performancewise), provide an EXPLAIN for the above together with proper DDLS of all relevant tables.
Upvotes: 2