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


22

我目前正在使用一个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
  • query_cache_limit:1048576
  • query_cache_min_res_unit:4096
  • query_cache_size:104857600
  • query_cache_type:开启
  • query_cache_wlock_invalidate:关闭
  • innodb_buffer_pool_size:8841592832
  • 24GB RAM


呵呵,很有见识。
克雷格·塞夫顿

Answers:


16

您应该仅使用以下命令禁用查询缓存

[mysqld]
query_cache_size = 0

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

查询缓存将始终与InnoDB对接。如果InnoDB的MVCC允许修改不影响其他事务的可重复读取,则允许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;

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

我还将分配以下内容:

  • query_cache_size = 1G
  • query_cache_limit = 8M

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

  • innodb_buffer_pool_size = 12G
  • key_buffer_size = 4G

剩下7G。这对于OS和DB连接应该足够了。

请记住,关键缓冲区仅缓存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上比在MyISAM上更频繁地执行DML(INSERT,UPDATE,DELETE),我会说完全删除了查询缓存,这是我在一开始就说过的。


感谢您的回复。我有那本书,并且已经广泛使用它;我很清楚您概述缓存未命中的原因,但是正如我提到的,由于Com_select和Qcache_inserts之间存在很强的相关性,我们已经将缓存无效确定为关键问题。哦,有问题的数据库混合了INNODB和MyISAM。
Craig Sefton 2012年

更新了您要求的其他信息。谢谢。
克雷格·塞夫顿

感谢您的答复,我期待其余的答复。我们确实发现的一件事是未缓存大约18%的查询,因此绝对感谢有关设置的建议。不幸的是,这个盒子不是专用的,但是您的建议应该有所帮助。碎片肯定也是一个问题。我仍然真的很担心我们看到的无效数量(与根本没有缓存的查询相对),因此仍然不确定是否值得这样做。非常感谢您的见解,非常感谢。
Craig Sefton 2012年

关于您的评论“ mysql没有用于对查询缓存进行碎片整理的内部机制”,您是否可以执行命令FLUSH QUERY CACHE来对其进行碎片整理?参见:dev.mysql.com/doc/refman/5.0/en/flush.html
Craig Sefton 2012年

更新了我的答案...
RolandoMySQLDBA 2012年

3

错误:query_cache_size = 1G

为什么?由于冲洗需要多长时间。也就是说,当发生一些写操作时,将扫描整个1GB,以查找对已修改表的任何引用。QC越大,速度越慢。我建议大小不要超过50M,除非您的数据很少更改。

对于MyISAM和InnoDB,质量控制都是开销。它会取出全局Mutex,但过早将其取出。这种互斥锁是MySQL无法有效使用超过8个内核的原因之一。

直到之后才注意到SQL_NO_CACHE互斥锁锁定,!该标志的唯一用途是进行基准测试。

通常最好将RAM分配给其他一些缓存。


2

我可以想到一个完美的案例,并且我们已经对它进行了彻底的测试并在生产中运行...我称之为“快速通道”集群策略:

如果您使用MaxScale之类的代理进行读写拆分,或者您的应用程序有能力,则可以将那些很少失效的表的某些读操作仅发送到已打开查询缓存的从属设备,并将其余部分发送给其他从属设备关掉。

我们这样做并因此在负载测试(不是基准测试……实际交易)期间每分钟处理4M呼叫集群。该应用程序确实会在master_pos_wait()上等待某些事情,因此它受到复制线程的限制,尽管我们看到它处于等待状态,并且以非常高的吞吐量等待Qcache无效,但是这些吞吐量级别甚至比集群还要高。没有Qcache的能力。

之所以可行,是因为这些机器上的微小查询缓存中几乎没有任何相关内容可以使它们失效(这些查询仅与不经常更新的表有关)。这些盒子是我们的“快车道”。对于应用程序执行的其余查询,它们不必与Qcache竞争,因为它们会在未打开的情况下进入框。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.