为什么使用 SQL_NO_CACHE 的查询在第一次运行时运行速度较慢?

Gro*_*ing 5 mysql innodb performance mysql-5.6 query-performance

查询尽可能快,仅SQL_NO_CACHE 1在 select 和 中使用limit 1。结果很好奇。第一次运行需要 0.125 - 0.203 秒。并且所有接下来的运行通常不到 0.040 秒。它是某种预热,还是与构建查询过程有关?

现在这不是问题,但我想知道为什么会这样,并尽可能避免它。

引擎 - InnoDB
MySQL 版本 - 在 5.6 和 5.7 上测试

Fed*_*oli 1

正如另一个答案所强调的,查询缓存并不是唯一的缓存。在大多数情况下,甚至不建议使用它 - 事实上,它在 MySQL 8.0 中已被删除。原因是它存在可扩展性问题(它由全局锁控制),并且它使数据过于频繁地失效,以至于在正常工作负载中无法使用。

但是InnoDB缓冲池包含经常访问的索引和数据。第一次查询后,一些索引和数据会被缓存,因此下次查询时将从内存中读取它们。也许每个查询只访问一些数据/索引页一次,在这种情况下,您应该能够看到第二次和第三次执行之间的细微差别(第一次这些页面没有被缓存)。

如何避免查询执行时间的差异?嗯,没有办法让查询在第一次运行时更快,因为它需要从磁盘读取。但是,如果您的缓冲池足够大,您的查询将始终很快。请记住,大的缓冲池对于 MySQL 性能非常重要。一般建议将其保留为总内存的 75-80%。但实际上,事情要复杂得多:

  • 其他高速缓存和缓冲区需要空间。特别是,如果您有许多用户,或者您的用户运行许多 JOIN 或 ORDER BY,则应考虑每个会话缓冲区。
  • 让缓冲池大于数据库是没有用的。通常,让它大于热数据(您经常访问的数据)是一种浪费。

另一件事是,有时每个服务器都会重新启动。当发生这种情况时,如果缓冲池被简单地清空,那么重新启动后您的查询将会变慢 - 直到热数据再次被缓存。但你可以通过设置来避免这种情况:

innodb_buffer_pool_dump_at_shutdown = 1
innodb_buffer_pool_load_at_startup = 1
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您的缓冲池将在关闭时(部分)写入磁盘并在启动时重新加载,因此即使在重新启动后您的查询也应该很快。