【问题标题】:Combined sql query takes too much time组合sql查询耗时太长
【发布时间】:2017-08-23 06:48:12
【问题描述】:

我在 MySQL 中的一个查询在执行时花费了太多时间。在这个查询中,我使用 IN 运算符从 MySQL 数据库中获取数据库。

我的查询:

SELECT *
FROM databse_posts.post_feeds
WHERE
    post_id IN (SELECT post_id FROM database_users.user_bookmarks where user_id=3) AND
    post_date < unix_timestamp();

在这种情况下,两个单独的查询执行所需的时间都非常少,例如

SELECT post_id FROM database_users.user_bookmarks where user_id=3

最多需要大约 400 毫秒

SELECT * FROM databse_posts.post_feeds Where post_date < unix_timestamp();

最多需要 300 毫秒

但是使用 IN 运算符将两个查询组合在一起大约需要 6 到 7 秒。 为什么这需要太多时间。 我还编写了不同类型的查询,但所有这些都不会花费那么多时间。

【问题讨论】:

  • 关系列有匹配的索引?进行内部连接将减少时间。
  • 我想如果你想知道它为什么慢,我们需要看看解释计划输出。如果你只是想要一个更快的解决方案,timo 的答案可能是最完整的

标签: mysql sql


【解决方案1】:

您可以尝试在子选择上进行内部连接,而不是 where IN(子选择)

SELECT *
FROM databse_posts.post_feeds
INNER JOIN (
    SELECT post_id 
    FROM database_users.user_bookmarks 
    where user_id=3
) T on T.post_id = post_feeds.post_id
AND
post_date < unix_timestamp();

并确保您在 post_feeds.post_iduser_bookmarks.user_id, user_bookmarks.post_id 上有正确的索引

【讨论】:

  • 为什么不完全删除子查询,并内联两个表/放一个组合的where子句?
  • 您建议的索引对我来说没有意义,但无论如何我认为在加入子查询时不能使用索引。
【解决方案2】:

我的做法:

您需要为字段post_feeds.post_iduser_bookmarks.post_iduser_bookmarks.user_idpost_feeds.post_date字段创建索引,然后使用INNER JOIN让MySQL 引擎以有效的方式操作行的过滤和合并:

SELECT
    pf.*
FROM
    databse_posts.post_feeds pf
    INNER JOIN database_users.user_bookmarks ub
        ON ( pf.post_id = ub.post_id )
WHERE
    ub.user_id = 3
    AND pf.post_date < unix_timestamp();

【讨论】:

  • 好的,但这仍然不能解释 OP 的观察结果。
  • 您已经看到“客户想要什么”轮胎摆动卡通,对吧?我认为这个 q 可能是其中之一
【解决方案3】:

我在这里粗略的猜测是WHERE IN 表达式正在做一些你可能不知道的事情。考虑您的完整查询:

SELECT *
FROM databse_posts.post_feeds
WHERE
    post_id IN (SELECT post_id FROM database_users.user_bookmarks where user_id=3) AND
    post_date < unix_timestamp();

对于每条记录,MySQL 必须检查post_id 的每个值,并将其与来自子查询的post_id 列表进行比较。这比只运行该子查询一次要昂贵得多。 MySQL 可以使用各种技巧来加快速度,但 WHERE IN 子句中的子查询与只运行该子查询一次不同。

如果这个假设是正确的,那么下面的查询也应该在 6-7 秒的范围内:

SELECT *
FROM databse_posts.post_feeds
WHERE
    post_id IN (SELECT post_id FROM database_users.user_bookmarks where user_id=3)

如果是这样,那么我们就会知道性能下降的原因。

【讨论】:

  • 不是最复杂的子查询,是吗?我希望 MySQL 的优化器很快就重写了那个。 MySQL 真的是一个低等级的数据库,它会重复运行 IN 子句中的子查询,而不是从静态结果集中制作哈希表吗?
  • @CaiusJard 查看公认的解决方案,这意味着WHERE IN 在某种程度上损害了性能。是的,MySQL 可以优化,但显然还是要付出代价。接受的答案实际上并没有回答这个问题,所以只要它没有被否决,我就会保留它。
  • 确实,我不同意接受的解决方案也是一个可以接受的解决方案,但这就是不知情成为绿色勾号的问题:)
猜你喜欢
  • 2021-06-28
  • 2015-07-11
  • 1970-01-01
  • 2021-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-24
相关资源
最近更新 更多