频繁查询缓存失效的开销值得吗?

Cra*_*ton 23 mysql innodb myisam performance cache

我目前正在研究一个 MySQL 数据库,我们看到查询缓存中有大量无效,主要是因为在许多表上执行了大量的 INSERT、DELETE 和 UPDATE 语句。

我要确定的是,允许将查询缓存用于针对这些表运行的 SELECT 语句是否有任何好处。由于它们很快就失效了,在我看来,最好的办法是在这些表的 SELECT 语句上使用 SQL_NO_CACHE。

频繁失效的开销值得吗?

编辑:应以下用户@RolandoMySQLDBA 的要求,这里是有关 MyISAM 和 INNODB 的信息。

数据库

  • 数据大小:177.414 GB
  • 索引大小:114.792 GB
  • 表大小:292.205 GB

我的ISAM

  • 数据大小:379.762 GB
  • 索引大小:80.681 GB
  • 表大小:460.443 GB

附加信息:

  • 版本:5.0.85
  • 查询缓存限制:1048576
  • query_cache_min_res_unit:4096
  • 查询缓存大小:104857600
  • query_cache_type:开启
  • query_cache_wlock_invalidate:关闭
  • innodb_buffer_pool_size: 8841592832
  • 24GB 内存

Rol*_*DBA 16

您应该只禁用查询缓存

[mysqld]
query_cache_size = 0
Run Code Online (Sandbox Code Playgroud)

然后重启mysql。为什么我会建议???

查询缓存将始终与 InnoDB 相提并论。如果修改不影响其他事务的可重复读取,如果 InnoDB 的 MVCC 允许从查询缓存中提供查询,那就太好了。不幸的是,InnoDB 并没有这样做。显然,您有很多查询很快就会失效并且可能不会被重用。

对于 MySQL 4.0 下的 InnoDB,事务禁用了查询缓存。对于 MySQL 4.1+,InnoDB 在允许基于每个表访问查询缓存时扮演交通警察。

从您的问题的角度来看,我会说删除查询缓存的理由与其说是开销,不如说是 InnoDB 如何管理它。

有关 InnoDB 如何与查询缓存交互的更多信息,请阅读“高性能 MySQL(第二版)”一书的第 213-215 页。

如果您的所有或大部分数据是 MyISAM,您可以按照使用 SQL_NO_CACHE 的最初想法。

如果您混合使用 InnoDB 和 MyISAM,则必须根据缓存未命中的程度为您的应用程序找到合适的平衡点。事实上,同一本书的第 209-210 页指出了缓存未命中的原因:

  • 该查询不可缓存,要么是因为它包含一个不确定的构造(例如 CURRENT_DATE),要么是因为它的结果集太大而无法存储。两种类型的不可缓存查询都会增加 Qcache_not_cached 状态变量。
  • 服务器以前从未见过查询,因此它从未有机会缓存​​其结果。
  • 查询的结果先前已缓存,但服务器将其删除。这可能是因为没有足够的内存来保存它,因为有人指示服务器删除它,或者因为它已失效

并且几乎没有不可缓存的查询的高缓存未命中的根本原因可能是:

  • 查询缓存尚未预热。那是服务器没有机会用结果集填充缓存。
  • 服务器正在看到它以前从未见过的查询。如果您没有大量重复查询,即使在缓存预热后也会发生这种情况。
  • 有很多缓存失效。

更新 2012-09-06 10:10 EDT

查看您的最新更新信息,您已query_cache_limit设置为 1048576 (1M)。这将任何结果集限制为 1M。如果你检索任何更大的东西,它就不会被缓存。虽然您已query_cache_size设置为 104857600 (100M),但这仅允许在完美世界中设置 100 个缓存结果。如果您执行数百个查询,碎片会很快出现。您还有 4096 (4K) 作为最小尺寸结果集。不幸的是,mysql 没有对查询缓存进行碎片整理的内部机制。

如果您必须拥有查询缓存并且拥有如此多的 RAM,则可以执行以下操作:

SET GLOBAL query_cache_size = 0;
SELECT SLEEP(60);
SET GLOBAL query_cache_size = 1024 * 1024 * 1024;
Run Code Online (Sandbox Code Playgroud)

为了清除查询缓存。您会丢失所有缓存的结果,因此请在非高峰时段运行这些行。

我还将分配以下内容:

  • query_cache_size = 1G
  • query_cache_limit = 8M

剩下 23G 的 RAM。我会提出以下几点:

  • innodb_buffer_pool_size = 12G
  • key_buffer_size = 4G

剩下7G。这对于操作系统和数据库连接来说应该足够了。

请记住,键缓冲区仅缓存 MyISAM 索引页,而 InnoDB 缓冲池缓存数据和索引。

还有一个建议:升级到 MySQL 5.5,这样你就可以为多个 CPU 和多个线程配置 InnoDB 以进行读/写 I/O。

请参阅我之前关于将 MySQL 5.5 与访问 InnoDB 的多个 CPU 结合使用的帖子

更新 2012-09-06 14:56 EDT

我清除查询缓存的方法相当极端,因为它会处理缓存数据并形成完全不同的 RAM 段。正如您在评论中指出的那样,FLUSH QUERY CACHE(如您所建议的)甚至RESET QUERY CACHE会更好。为了澄清起见,当我说“没有内部机制”时,我的意思就是这样。碎片整理是必要的,必须手动完成。它需要 crontab'd

如果您在 InnoDB 上执行 DML(插入、更新、删除)比在 MyISAM 上更频繁,我会说完全删除查询缓存,我在开头说过。