【问题标题】:MySql Query Timed Out in Live but not in LocalMySql 查询在现场超时但不在本地
【发布时间】:2018-07-30 23:06:35
【问题描述】:

我们正在使用 MySQL InnoDB。

我们的查询看起来像这样。

在我们的实时环境中,此查询需要 30 多秒才能完成。

select  count(*) as aggregate
    from  `parents`
    where  exists (
        SELECT  *
            from  `childs`
            where  `parents`.`id` = `childs`.`parent_id`
              and  exists (
                SELECT  *
                    from  `users`
                    where  `childs`.`user_id` = `users`.`id`
                      and  `id` = '123456' )
              and  `status` = 'OK' )

所以我们已经导出了整个数据库并导入到我们本地的 mysql 数据库中。 令人惊讶的是,几乎是瞬间就获得了相同的查询结果。

因此,我们怀疑该表未优化,我们已执行以下操作。

optimize table users;
optimize table parents;
optimize table childs;

很遗憾,查询速度没有提高。

谁能看出哪里出了问题?

为什么在本地导出/导入(具有完全相同的结构数据)几乎是即时查询,并且直播需要将近 30-60 秒才能完成?


EXPLAIN 在本地和现场表演中有所不同, 与父表和子表相关的可能键的 DEPENDENT SUBQUERY 之一显示

Using where; FirstMatch(closing_batches)

但现场表演只有Using where 没有FirstMatch。

【问题讨论】:

  • 能否在live和local上做一个EXPLAIN,看看是否应用了相同的执行计划?
  • 嗨@Jacob 感谢您的提示,我已经按照您的建议进行了解释,发现缺少“FirstMatch”。这可能是什么原因造成的?

标签: mysql innodb database-optimization


【解决方案1】:

实际上,您甚至可以在不使用父表或用户表的情况下从单个查询中获取所有数据——如果“状态”字段在子表中。

来自基本的传递关联,

if A = B and B = C, then A = C.

您通过 ID 从 Child 加入到 User,然后查看 User ID = "123456"。

这与只要求 Childs.User_ID = "123456" 相同。

同样,从通过 Child.Parent_ID 连接到父级的子级,您的查询似乎正在尝试获取与给定子级关联的不同父级 ID 的计数。

所以,下面的应该可以得到你需要的。

select 
        count( distinct c.Parent_id ) Aggregate
    from
        childs c
    where
            c.user_id = '123456'
        AND c.status = 'OK'

如果状态字段在 PARENT 表上,则需要加入该字段

select 
        count( distinct c.Parent_id ) Aggregate
    from
        childs c
            join parents p
                on c.parent_id = p.id
                AND p.status = 'OK'
    where
            c.user_id = '123456'

为了性能,我还会在 (user_id, parent_id) 上的 childs 表上有一个索引。这也可以显着优化查询。

【讨论】:

    【解决方案2】:

    这可能是等价的:

    select  count(*) as aggregate
        from  `parents` AS p
        where  exists (
            SELECT  *
                from  `childs` AS c
                JOIN  users AS u  ON c.user_id = u.id
                WHERE  c.user_id = 123456
                  AND  p.`id` = c.`parent_id`
                  and  `status` = 'OK' 
            ) 
    

    OPTIMIZE TABLE 很少有用。

    status 在哪个表中?

    【讨论】:

    • 查询是由 Laravel 的 Eloquent 生成的。 statusparents 的列。相同的查询几乎立即在本地产生结果(从生产环境转储并导入到本地),但在生产环境中却没有。
    • @Gab - 好的。现在我投票支持 DRapp 的第二个查询。如果 Eloquent 无法生成与此相当接近的东西,我建议它“挡道”。目前,子查询LEFT 和不必要的Users 似乎很草率。
    猜你喜欢
    • 2018-04-29
    • 1970-01-01
    • 1970-01-01
    • 2020-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-27
    • 1970-01-01
    相关资源
    最近更新 更多