优化mysql子查询执行时间

时间:2019-12-16 09:49:41

标签: mysql sql subquery execution-time

我有以下查询:

select
qs.*
from
    (
        select
            tsk.id,
            tsk.request_id,
            tsk.hash_id
        from
            user_tasks as usr
            inner join unassigned_tasks as tsk on usr.task_id = tsk.id
        where
            usr.assigned_to = 53
            AND tsk.product_id NOT IN (
                SELECT
                    product_id
                FROM
                    product_progresses
                WHERE
                    request_id = tsk.request_id
            )
        ORDER BY
            tsk.id
    ) as qs <-- this takes about 233ms.
WHERE
    qs.id = ( <-- should this subquery execute for every row from outer result-set row?
        SELECT
            min(qt.id)
        FROM
            (
                select
                    tsk.id,
                    tsk.request_id,
                    tsk.hash_id
                from
                    user_tasks as usr
                    inner join unassigned_tasks as tsk on usr.task_id = tsk.id
                where
                    usr.assigned_to = 53
                    AND tsk.product_id NOT IN (
                        SELECT
                            product_id
                        FROM
                            product_progresses
                        WHERE
                            request_id = tsk.request_id
                    )
                ORDER BY
                    tsk.id
            ) as qt <-- this takes about 233ms.
        WHERE
            qt.id > 83934
    )

qsqt的执行时间大约相同,即大约233ms

此外,执行整个查询大约需要相同的时间。

我有一个概念,where qs.id = (...)内的内部查询对qs生成的结果集中的每一行执行一次。

在当前情况下,qs输出10行。

所以我决定测试是否对每行执行10次子查询。

这是我放入子查询中的内容:

WHERE qs.id = (
    SELECT
        SLEEP(1)
)

代替where qs.id = ( select min(qt.id) ... )

这花费了10.246,这证明内部查询正在针对每一行运行。

因此,初始查询不应该花费(qt time) 233 * 10 (rows from qs) = 2330毫秒吗?

是因为select min()..仅计算一次?

1 个答案:

答案 0 :(得分:0)

在MySQL中,FROM子句中的子查询先于WHERE子句中的子查询求值。

有用的文章: https://www.eversql.com/sql-order-of-operations-sql-query-order-of-execution/

在您的情况下,这导致qs在加入WHERE子句之前得到充分评估。如果希望qsqt限制,则应可以通过取消嵌套qs或在qt中移动qs来实现这一目标。

尽管实际上,与其对WHERE子句使用子查询,不如使用联接。

请参见SQL select only rows with max value on a column