【问题标题】:Sub-query Optimization Talk with an example case子查询优化谈案例
【发布时间】:2010-12-20 06:03:53
【问题描述】:

我需要建议并想分享我在查询优化方面的经验。本周,我发现自己陷入了一个有趣的困境。 我是mySql新手(2年理论,不到1年实战)

环境:

我有一个表,其中包含带有“类型”列的文章,另一个表 article_version 包含在数据库中添加文章的日期,第三个表包含所有文章类型以及类型标签和内容...

前两个表很大(800000+ 个字段并且每天都在增长),第三个自然很小。文章表有很多列,但我们只需要文章中的“ID”和“类型”以及文章版本中的“添加日期”来简化事情......

我想做的事:

一个查询,对于指定的“添加日期”,返回每种类型的文章数(大约有 50 种类型要扫描)。 已经存在的是 50 个单独的计数,每个文档类型一个 oO(效率不高,很长(一般约 5 秒),)。

我想在一个查询中完成所有操作,我想出了这个:

SELECT type,
  (SELECT COUNT(DISTINCT articles.ID)
    FROM articles
      INNER JOIN article_version
        ON article_version.ARTI_ID = legi_arti.ID 
    WHERE type = td.NEW_ID
      AND dateAdded = '2009-01-01 00:00:00')  AS nbrArti 
FROM type_document td 
WHERE td.NEW_ID != '' 
GROUP BY td.NEW_ID;

外部选择 (type_document) 允许我获取所需的 55 种类型的文档。 子查询正在计算给定日期“2009-01-01”的每个 type_document 的文章。

一个常见的结果是这样的:

* 类型 * nbrArti * ************************* * 123456 * 23 * * 789456 * 5 * * 16578 * 98 * * .... * .... * * .... * .... * *************************

这个查询完成了工作,但是子查询中的连接使得这个非常慢,如果我是对的,原因是服务器对每种类型都进行了连接,所以 50 多次,这个解决方案比为每种类型独立执行 50 次查询还要慢,太棒了:/

解决方案

我自己想出了一个解决方案,以同样的结果显着提高性能,我只是创建了一个与子查询相对应的视图,为每种类型创建了 id 的连接...而且 Boom,它的 f.a.s.t.

我认为,如果我错了,请纠正我,原因是服务器只运行一次 JOIN 语句。

此解决方案比已有的解决方案快约 5 倍,比我的第一次尝试快约 20 倍。甜

问题/想法

  • 从另一个角度来看,我现在需要检查插入文档时我是否松动多于胜利...
  • 有没有办法通过将 JOIN 语句从子查询中取出来改进原始查询? (并摆脱视图)
  • 还有其他提示/想法吗? (例如在服务器优化中......)

抱歉,我的英语很接近,它不是我的主要语言。

【问题讨论】:

    标签: optimization mysql count query-optimization


    【解决方案1】:

    您不能在 (type, date_added) 上创建单个索引,因为这些字段位于不同的表中。

    如果没有视图,子查询很可能选择article 作为前导表,而type 上的索引不是很有选择性。

    通过创建视图,您可以强制子查询首先计算所有类型的总和(使用date 上的选择性索引),然后使用JOIN BUFFER(对于仅55 类型来说足够快) .

    您可以通过这样重写查询来获得类似的结果:

    SELECT  new_id, COALESCE(cnt, 0) AS cnt
    FROM    type_document td
    LEFT JOIN
            (
            SELECT  type, COUNT(DISTINCT article_id) AS cnt
            FROM    article_versions av
            JOIN    articles a
            ON      a.id = av.article_id
            WHERE   av.date = '2009-01-01 00:00:00'
            GROUP BY
                    type
            ) q
    ON      q.type = td.new_id
    

    不幸的是,MySQL 无法进行表假脱机或哈希连接,因此为了提高性能,您需要对表进行非规范化:将 type 添加到 article_version 并在 (date, type) 上创建复合索引.

    【讨论】:

    • 您好,非常感谢您的解释和建议。在这些特殊情况下,我仍然不太熟悉 mysql 索引。我会看一下并针对您的想法进行一些测试。也感谢您的查询建议,非常有趣的实现方式!
    猜你喜欢
    • 2014-07-12
    • 2012-01-28
    • 2015-05-31
    • 2014-11-10
    • 2018-04-20
    • 2011-06-09
    • 1970-01-01
    • 1970-01-01
    • 2011-11-27
    相关资源
    最近更新 更多