mysql - 如何优化查找不存在条件联接行的行的查询?

标签 mysql optimization join

我有一个关键字表,我定期根据远程搜索 API 刷新该表,并且我还有另一个表,每次刷新其中一个关键字时,该表都会获取一行。我使用此表来阻止多个进程相互干扰并刷新相同的关键字以及统计信息收集。因此,当我启动程序时,它会查询当前没有处理请求的所有关键字,并且在过去 15 分钟内或任何时间间隔内没有成功的请求。有一段时间一切都工作正常,但现在 keywords_requests 表中有近 200 万行,事情严重陷入困境。我在 keywords_requests 表中的几乎每一列上都有索引,但无济于事。

我正在记录缓慢的查询,而这个查询花费了很长时间,如您所见。我能做什么?

# Query_time: 20 Lock_time: 0 Rows_sent: 568 Rows_examined: 1826718

SELECT Keyword.id, Keyword.keyword
FROM `keywords` as Keyword
LEFT JOIN `keywords_requests` as KeywordsRequest
ON (
  KeywordsRequest.keyword_id = Keyword.id
  AND (KeywordsRequest.status = 'success' OR KeywordsRequest.status = 'active')
  AND KeywordsRequest.source_id = '29'
  AND KeywordsRequest.created > FROM_UNIXTIME(1234551323)
)
WHERE KeywordsRequest.id IS NULL
GROUP BY Keyword.id
ORDER BY KeywordsRequest.created ASC;

最佳答案

看来您对 Keywords 最具选择性的索引是 KeywordRequest.created 上的索引。

尝试以这种方式重写查询:

SELECT Keyword.id, Keyword.keyword
FROM `keywords` as Keyword
LEFT OUTER JOIN (
  SELECT *
  FROM `keywords_requests` as kr
  WHERE created > FROM_UNIXTIME(1234567890) /* Happy unix_time! */
) AS KeywordsRequest
ON (
  KeywordsRequest.keyword_id = Keyword.id
  AND (KeywordsRequest.status = 'success' OR KeywordsRequest.status = 'active')
  AND KeywordsRequest.source_id = '29'
)
WHERE keyword_id IS NULL;

它将(希望)散列连接两个不太大的源。

Bill Karwin 是对的,您不需要 GROUP BYORDER BY

MySQL 中的计划无法精细控制,但您可以尝试(尝试)通过以下方式改进您的查询:

  1. (keyword_id、status、source_id、created)上创建复合索引并使其如下:

    SELECT Keyword.id, Keyword.keyword
    FROM `keywords` as Keyword
    LEFT OUTER JOIN `keywords_requests` kr
    ON (
      keyword_id = id
      AND status = 'success'
      AND source_id = '29'
      AND created > FROM_UNIXTIME(1234567890)
    )
    WHERE keyword_id IS NULL
    UNION
    SELECT Keyword.id, Keyword.keyword
    FROM `keywords` as Keyword
    LEFT OUTER JOIN `keywords_requests` kr
    ON (
      keyword_id = id
      AND status = 'active'
      AND source_id = '29'
      AND created > FROM_UNIXTIME(1234567890)
    )
    WHERE keyword_id IS NULL
    

    理想情况下,应该在索引上使用NESTED LOOPS

  2. (status、source_id、created)上创建复合索引并使其如下:

    SELECT Keyword.id, Keyword.keyword
    FROM `keywords` as Keyword
    LEFT OUTER JOIN (
      SELECT *
      FROM `keywords_requests` kr
      WHERE
        status = 'success'
        AND source_id = '29'
        AND created > FROM_UNIXTIME(1234567890)
      UNION ALL
      SELECT *
      FROM `keywords_requests` kr
      WHERE
        status = 'active'
        AND source_id = '29'
        AND created > FROM_UNIXTIME(1234567890)
    )
    ON keyword_id = id
    WHERE keyword_id IS NULL
    

    这有望在更受限制的哈希表上使用HASH JOIN

关于mysql - 如何优化查找不存在条件联接行的行的查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/547552/

相关文章:

php - 选择每个数组元素的信息行

php - 优化我的sql查询

sql - 我们可以在用于加入 Hive 查询的字段上使用 split 函数吗

sql - 如果没有ON关键字,您是否可以拥有INNER JOIN?

php - 在 PHP 中连接具有不同 ID 的表字段

mysql - docker : SQLSTATE[HY000] [2002] No such file or directory 上的 nextcloud 和 mariadb(两者)

mysql - 有没有办法在一个命令中使多个列不为空?

mysql - 在 vb.net 中将 sql 数据添加到 DB 是否需要 .ExecuteNonQuery()

mysql - 组织和优化大表

algorithm - 优化算法 : Fastest Way to Derive Sets