Reputation: 716
I have a script that triggers the below sql
. The performance of this query wasn't too bad until now, and I believe it's because of the large number of records that exist in one of the tables and, according to the explain I'm running on the query, it's performing a scan against the entire users table (approx 10 million records).
Is there a better way to write this so that it doesn't scan and I can get the executions back down to < 1 second?
SELECT
`users` . *,
users.username AS `fullname`,
(SELECT
CONCAT_WS('|||',
image,
width,
height,
original,
mime)
FROM
`users_avatars`
WHERE
(user_id = users.user_id)
AND (size = '_A')
LIMIT 1) AS `user_avatar_a`,
(SELECT
CONCAT_WS('|||',
image,
width,
height,
original,
mime)
FROM
`users_avatars`
WHERE
(user_id = users.user_id)
AND (size = '_B')
LIMIT 1) AS `user_avatar_b`,
(SELECT
CONCAT_WS('|||',
image,
width,
height,
original,
mime)
FROM
`users_avatars`
WHERE
(user_id = users.user_id)
AND (size = '_C')
LIMIT 1) AS `user_avatar_c`,
((SELECT
COUNT(ufu_id)
FROM
`users_following_user`
WHERE
(user_id = 684767)
AND (following_id = users.user_id)
LIMIT 1) + (SELECT
COUNT(users_following_id)
FROM
`users_following`
WHERE
(user_id = 684767)
AND (following_id = users.user_id)
LIMIT 1)) AS `following_user`
FROM
`users`
WHERE
(users.user_id IN ((SELECT
`users_boards`.`user_id`
FROM
`users_boards`
WHERE
(board_id = '353048') AND (allow = 1))))
**** UPDATE **** I believe I've isolated, or at least narrowed down where the issue is coming from.
SELECT *
FROM
`users`
WHERE
(users.user_id IN ((SELECT
`users_boards`.`user_id`
FROM
`users_boards`
WHERE
(board_id = '353048') AND (allow = 1))))
EXPLAIN on the query gives the following:
# id, select_type, table, type, possible_keys, key, key_len, ref, rows, filtered, Extra
1, PRIMARY, users, ALL, PRIMARY, , , , 3952473, 100.00,
1, PRIMARY, users_boards, ref, user_id, user_id, 16, skoovy_prd.users.user_id,const, 1, 100.00, Using where; FirstMatch(users)
Upvotes: 1
Views: 471
Reputation: 40371
First of all, you should consider using JOIN over the sub queries. This by itself should show you improvement in performance unless you have a super good reason to use sub query. I can't imagine a good reason that would stop you from using JOINS.
Now, that you identified the query that is causing you to loose performance. Let's try to tune it.
Try both of theses queries as they should help you improve the speed.
SELECT su.* FROM users AS su
INNER JOIN users_boards AS b ON b.user_id = su.user_id
WHERE b.board_id = 353048 AND b.allow = 1
SELECT *
FROM users AS su
WHERE EXISTS (SELECT 1 FROM users_boards WHERE user_id = su.user_id AND board_id = 353048 AND allow = 1)
CREATE TEMPORARY TABLE users_boards (KEY(user_id)) ENGINE=MEMORY AS
SELECT user_id
FROM users_boards
WHERE user_id = su.user_id AND board_id = 353048 AND allow = 1;
Also this index should be very helpful. If you can add it (if it does not exists) you should consider it
ALTER TABLE users_boards ADD INDEX combo (user_id, board_id, allow);
If this does not help you should consider posting your show create table
for users and for users_boards I would like to believe that your column types are not the same.
SHOW CREATE TABLE users;
SHOW CREATE TABLE users_board;
Upvotes: 1