mysql 当按id desc组合订单且不存在时,查询速度非常慢

14ifxucb  于 2023-04-19  发布在  Mysql
关注(0)|答案(2)|浏览(103)
SELECT
    *
FROM
    `users`
WHERE
    `id` != 1
    AND `users`.`activated` = 1
    AND NOT EXISTS (
        SELECT
            1
        FROM
            `blockings`
        WHERE (blockings.user_id = users.id
            AND blockings.blocked_id = 1)
        OR(blockings.blocked_id = users.id
            AND blockings.user_id = 1))
ORDER BY
    users.id DESC
LIMIT 10 OFFSET 0

在30k行的表上完成此查询需要5秒
当我删除NOT EXISTS部分时,需要一段时间才能完成
在www.example.com上有索引users.id,blockings.user_id和blockings.blocked_id
如何加快查询速度?

zu0ti5jz

zu0ti5jz1#

这有点像“在黑暗中摸索”,因为您没有在问题中包含当前查询的表定义或EXPLAIN输出。
使用blockings.user_idblockings.blocked_id上的单列索引,您应该在当前查询的EXPLAIN输出中看到blockings的index_merge。
使用PK (user_id, blocked_id)(blocked_id, user_id)上的索引,在NOT EXISTS中使用UNION可能会快得多:

SELECT *
FROM users u
WHERE u.id != 1
  AND u.activated = 1
  AND NOT EXISTS (
        SELECT 1
        FROM blockings b
        WHERE b.user_id = u.id AND b.blocked_id = 1
        UNION ALL
        SELECT 1
        FROM blockings b
        WHERE b.blocked_id = u.id AND b.user_id = 1
    )
ORDER BY u.id DESC
LIMIT 10 OFFSET 0;

正如MatBailie所建议的,值得尝试将UNION ALL分成两个独立的NOT EXISTS:

SELECT *
FROM users u
WHERE u.id != 1
AND u.activated = 1
AND NOT EXISTS (
    SELECT 1
    FROM blockings b
    WHERE b.user_id = u.id AND b.blocked_id = 1
)
AND NOT EXISTS (
    SELECT 1
    FROM blockings b
    WHERE b.blocked_id = u.id AND b.user_id = 1
)
ORDER BY u.id DESC
LIMIT 10 OFFSET 0;
xsuvu9jc

xsuvu9jc2#

下面是一个可能的替代查询,您可能需要在where子句中使用的列上添加索引。

SELECT
    users.id,  /* all the necessary columns goes here */
    users.name,
    users. Email
FROM
    users
    LEFT JOIN blockings ON (
        (blockings.user_id = users.id AND blockings.blocked_id = 1)
        OR (blockings.blocked_id = users.id AND blockings.user_id = 1)
    )
WHERE
    users.id != 1
    AND users.activated = 1
    AND blockings.id IS NULL
ORDER BY
    users.id DESC
LIMIT 10 OFFSET 0;

相关问题