为什么需要复制到 tmp 表的 mysql 查询有时会在几秒钟内随机消耗 100% 的 CPU?

为什么需要复制到 tmp 表的 mysql 查询有时会在几秒钟内随机消耗 100% 的 CPU?

我的 PHP 脚本中有一些疯狂的 SQL 查询,急需优化。然而问题不在于如何优化它们。

这些查询有很多“join”和一些奇怪的“order by”,并且针对包含数万条记录的表执行。lots_of_joins+crazy_order_by 使得它们需要一个“复制到临时表”步骤。

现在奇怪的是,同样的查询有时运行得很快(不到一秒),有时却要花很长时间(几十秒)。在这两种情况下,“解释”和配置文件都显示“复制到临时表”步骤。当查询需要很长时间时,99% 的时间都花在“复制到临时表”阶段。奇怪的是,在此期间,mysql 几乎消耗了 100% 的 CPU。

因此,我理解 tmp 表有时保存在内存中,有时写入磁盘(取决于当前内存可用性)。因此,这可以完美解释为什么同一查询有时很快,有时却需要很长时间。但是,有两件事我不明白。

  1. 如果瓶颈在于将临时表写入磁盘,那应该意味着在 I/O 上花费了大量时间,但这段时间内的平均 CPU 负载应该相对较低,肯定远非 100%。在进行如此多的 I/O 时,CPU 怎么会这么忙?

  2. 我在my.cnf中增加了:

     max_heap_table_size = 1024M
     tmp_table_size = 1024M
    

(我认为默认值是 16M)

并且我真的不相信 tmp 表需要超过那么多的 RAM。

据我了解,临时表被写入磁盘而不是内存:a-如果查询和表需要它,因为它们不满足某些条件 b-如果它超过了 max_heap_table_size 和 tmp_table_size 之间的最小值

如果 (a) 是这种情况,那么就会发生总是,不是时不时。另一方面,我认为不太可能是 (b),因为我已经大大增加了上述参数,但没有任何明显的变化。所需表的大小在相同查询的出现中不应该有太大变化(数据几乎相同)。因此,如果在增加内存大小之前它偶尔发生一次(这意味着所需临时表的大小刚好在最大值附近),那么在如此急剧增加之后,不稳定的行为应该已经完全消失。

所以我的问题基本上是:

  1. 创建磁盘表真的是导致复制到临​​时表步骤花费很长时间的唯一原因吗?(或者即使在内存中完成也会花费很长时间?如果是,为什么,为什么是随机的?)

  2. 如果是的话,那么

    • 它怎么可能占用这么多的 CPU 呢?
    • 为什么即使临时表不大于 min(tmp_table_size,max_heap_table_size) 也可以将其写入磁盘?

我真的不认为示例查询和配置文件是必要的,但如果需要的话我可以发布它们。

答案1

我认为您的问题不在于 tmp_table_size,而在于通过 query_cache 缓存“丑陋”的查询(结果集)。如果您的查询是 SELECT 类型,请使用 SQL_NO_CACHE。缓存后,它运行速度很快,但会使缓存过载,并且 mysql 已知内部重新组织缓存存在问题。此外,使用 EXPLAIN 检查您的查询,并在必要时对连接使用强制索引。

这作为评论更合适,但我目前的声誉太低了。

相关内容