【问题标题】:MySQL - Why is COUNT with "greater than" quick but "less than" takes forever?MySQL - 为什么“大于”的 COUNT 快速但“小于”需要永远?
【发布时间】:2011-04-01 10:05:07
【问题描述】:
SELECT count(*) c FROM full_view WHERE verified > ( DATE (NOW()) - INTERVAL 30 DAY)

如果我运行该查询,它需要一瞬间,但如果我切换比较运算符,它需要 eons。现在第一种方式 count = 0,第二种方式 count = 120000,但如果我只计算整个表也需要微秒。

但是有一些奇怪的事情正在发生,因为如果查询确实完成了,它之后会运行得非常快。 MySQL正在缓存查询还是正确的?好吧,我不想依靠缓存来确保网站不会挂起。

这似乎很荒谬:如果它可以快速计算大于某个日期的所有内容,为什么还要花更长的时间来计算相反的时间?无论哪种方式,它都必须查看整个表格,对吗?它只需要返回一个数字,因此带宽不应该成为问题。

解释查询:

1, 'SIMPLE', 'b', 'range', 'updated,verified_index', 'updated', '3', '', 28, 'Using where'`    
1, 'SIMPLE', 'l', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'xyz_main.b.loc_id', 1, 'Using index'
1, 'SIMPLE', 'f', 'ALL', '', '', '', '', 2214, ''

编辑:

这可能有点意思,我在运行查询时发现了这个信息:

Handler_read_rnd_next:

  • 254436689(当做不到时)
  • 2(大于)

Key_read_requests: 314393 vs 33(使用大于时,33 是所有统计数据的最大数字)

Handler_read_key: 104303 对 1

绕过视图并直接在主表上运行查询可以消除缓慢。那么我需要做些什么来加快速度呢?视图本质上是这样的:

SELECT x, y, z, verified FROM table1 LEFT JOIN table2 on tab2_ID = table2.ID LEFT JOIN table3 on tab3_ID = table3.ID

已解决: 弗兰基带领我朝着正确的方向前进。第二个连接表(公司表)是通过公司的全文名称连接的。我最近才决定向该表添加一个整数键。 name 列应该被索引,但我可能搞砸了。无论如何,我重新组织了一切。我将主表中的外键转换为匹配公司表的整数 ID,而不是完整的公司名称。我重新索引了每个表中的这些列,然后我更新了视图以反映新的连接点。现在它立即在两个方向上运行。 :) 所以我猜整数键是关键。问题消失了,但我觉得我最初的问题并没有真正解决。

感谢你们的帮助。

【问题讨论】:

  • 我假设full_view 是一个视图,它的定义是什么?
  • “解释计划”告诉你什么?
  • full_view 包含与其他两个表连接的主表(带有已验证的列)。主表是人员,另外两个表连接位置和公司信息。这很简单。
  • 你能不能试着在视野之外做这件事?只是为了让我们看看是否有任何变化?我要去睡觉了。明天去看看。
  • @Moss 我们可以获取数据的 DUMP 以使用这些值吗?

标签: mysql count performance comparison-operators


【解决方案1】:

我的猜测是Date(Now()) 的减法需要很长时间才能处理。对于已经小于 Date(Now())verified 的值,评估可能会短路,因为此时它必须为假(比较“大于”时)。

在与“小于”进行比较的情况下,无论当前值如何,都必须减去日期时间,因为它无法在计算之前从逻辑上断定表达式为真或假日期时间减法

不过,这只是一个猜测 - 持保留态度。

【讨论】:

  • 使用明确的日期也需要很长时间。
  • @Moss 很有趣,也许我的想法是不合时宜的。只是颠倒比较的顺序怎么样?而不是A < B,做B > A 看看它是否需要很长时间 - 它应该执行完全相同(我猜)
  • 有趣的想法,但现在尝试为时已晚。我用更好的键/索引解决了这个问题。
【解决方案2】:

如果您在表中的verified 上有一个索引,那么限制性更强的COUNT(> 之一)会更快。没有 WHERE 子句的 COUNT(*) 可以快速返回,因为可以从表/索引统计信息中收集计数。

【讨论】:

  • 将比较放在计数中是更好的语法,但不会加快速度。我在verified 上有一个索引。
  • 事实上这种方法在两个方向上都变慢了。
【解决方案3】:

可能是有统计信息告诉数据库引擎没有经过验证的记录 > 30 天前。在这种情况下,它甚至根本不需要读取表格,而是从统计直方图中获取信息。

【讨论】:

    【解决方案4】:

    请运行以下查询并发布结果。

    EXPLAIN SELECT count(*) c 
    FROM full_view 
    WHERE verified > ( DATE (NOW()) - INTERVAL 30 DAY)
    

    被遗忘已久的EXPLAIN 几乎总能带来一些东西! ;)


    编辑 1:
    这大概是进攻路线:

    1, 'SIMPLE', 'f', 'ALL', '', '', '', '', 2214, ''
    

    那里的ALL 表明存在完整的表扫描。

    您可以深入了解Explain syntax on this diagram

    尝试看看差异在哪里......


    编辑 2:
    This doc will sure make things much clearer on the Explain output. Please check it out.


    编辑 3:
    解释命令的分步分析。

    1, 'SIMPLE', 'b', 'range', 'updated,verified_index', 'updated', '3', '', 28, 'Using where'`    
    1 - id
    SIMPLE - simple select, not using sub-queries
    b - table name
    range - only rows that are in a given range are retrieved, using an index
    updated,verified_index - are both possible keys
    updated - was the key eventually used
    3 - key lenght
    '' - this is the ref column and would show which columns or constants are compared to the index name in the key column to select rows from the table.
    28 - number of rows mysql believes it must examine to execute the query
    Using where - self explanatory
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-09-03
      • 2020-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-12
      • 2020-06-24
      相关资源
      最近更新 更多