【问题标题】:SLOW QUERY / IN HAVING ClauseSLOW QUERY / IN HAVING 子句
【发布时间】:2021-09-04 00:56:13
【问题描述】:

我在 MySQL

中有一个多对多关系数据库

还有这个查询

SELECT main_id FROM posts_tag
    WHERE post_id IN ('134','140','187')
    GROUP BY main_id
    HAVING COUNT(DISTINCT post_id) = 3

此表中有 ~5,300,000 行,并且该查询似乎很慢,例如 5 秒(如果我在搜索中添加更多 id 则更慢)

我想问有没有什么方法可以让它更快?

解释显示:

顺便说一句,我想添加更多条件,例如 NOT IN 和可能的 JOIN 具有相同结构但数据不同的新表。不太像这样,但首先我想知道是否有任何方法可以使这个简单的查询更快?

任何建议都会有所帮助,甚至是另一种方法或结构等。

PS:硬件是 Intel Core i9 3.6Ghz,64GB RAM,480GB SSD。所以我认为服务器规格不是问题。

【问题讨论】:

  • 不慢,你的查询好像返回了78003行,很多。这是预期的结果吗?
  • 基本上不是,没有 EXPLAIN 它只返回 64 行,这是预期的结果。我真的不知道为什么会显示那些 78003。可能这就是检查的数量...
  • 请发布 A) SHOW CREATE TABLE posts_tag 的 TEXT 结果;和 B) 显示表状态,其中名称如“posts_tag”;进行分析。
  • @alexfsk EXPLAIN 中的 78003 是返回 SELECTion 的“检查的行数”。
  • @WilsonHauck A) prnt.sc/1rdt264 B) prnt.sc/1rdsnxf

标签: mysql performance having database-indexes


【解决方案1】:

使用“复合”和“覆盖”索引:

INDEX(post_id, main_id)

并去掉INDEX(post_id),因为它会是多余的。

“覆盖”有助于加快查询速度。

假设这是一个普通的“多对多”表,那么:

CREATE TABLE post_main (
    post_id -- similar to `id` in table `posts`
    main_id -- similar to `id` in table `main`
    PRIMARY KEY(post_id, main_id),
    INDEX(main_id, post_id)
) ENGINE=InnoDB;

在多对多表中的任何地方都不需要AUTO_INCREMENT

(您可以添加 FK 约束,但我说“为什么要麻烦”。)

更多讨论:http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table

而且不在

这有点棘手。我认为这是一种方式;可能还有其他人。

SELECT  main_id
    FROM post_main
    WHERE post_id IN (244,229,193,93,61)
    GROUP BY main_id AS x
    HAVING COUNT(*) = 5
      AND NOT EXISTS ( SELECT 1
                  FROM post_main
                  WHERE main_id = x.main_id
                    AND post_id IN (92,10,234) );

【讨论】:

  • Rick,请检查发布的 SHOW CREATE TABLE 中的 posts_tag,在我看来,alexfsk 需要保留他的 INDEX(post_id),因为它用于管理约束。
  • @WilsonHauck - 哎哟!感谢您指出。
  • 瑞克,试着把所有东西都挂在一起。只是碰巧注意到带有 CONSTRAINT 的列的用处。感谢您为社区所做的一切。
  • 我尝试了示例中的结构,它的速度提高了很多。谁能告诉我如何在同一查询中按 NOT 过滤? SELECT main_id FROM posts_tag WHERE post_id IN (134,140,​​187) AND post_id NOT IN (23,50,301,88,941) GROUP BY main_id HAVING COUNT(DISTINCT post_id) = 3 我如何在这个查询中加入具有相同结构的新表?谢谢!
  • @alexfsk - 你确定那个查询吗?如果 post_id 是 134,140,​​187 之一,则它不能在另一个列表中。该查询的目标是什么? (用文字表达,而不是 SQL。)
【解决方案2】:

Alexfsk,您在第二行的查询具有用单引号括起来的 IN 变量。当您的列名定义为 INT 或 mediumint(或任何类型的 int)数据类型时,在数据周围添加单引号会导致所考虑的每一行的数据类型转换延迟,并延迟查询的完成。

【讨论】:

    猜你喜欢
    • 2021-08-15
    • 1970-01-01
    • 2022-12-31
    • 1970-01-01
    • 1970-01-01
    • 2019-07-15
    • 2015-06-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多