kambythet
kambythet

Reputation: 716

SQL query performance issue full table scan

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

Answers (1)

Jaylen
Jaylen

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.

1 Join Query if the relation between users and users_board is 1:1 and you are looking to display all results

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

2 EXISTS() sub query. This query should be a short and fast Circuit if the relation between the users table and the user_board is 1:many

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)

3 you can try using Temporary Tables just before any query I listed above to see if there is any improvement.

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

Related Questions