MySQL 子集查询缓存

MySQL cache of subset queries

我正在尝试在 acceptable 时间内对大型数据库进行查询 运行。我正在考虑优化查询本身(例如 ),这使我从根本无法完成查询(有 20 小时的上限)到完成它但时间仍然无法接受 table.

在实验中,我发现了以下我想了解的奇怪行为:我想在 2 年的时间范围内进行查询。如果我像那样直接尝试 运行 它,那么它仍然不会在我允许测试的 10 分钟内完成。如果我将它减少到范围的前 6 个月,它会很快完成。如果我然后通过在范围内添加几个月来逐步重新 运行 查询(即 运行 8 个月,然后 10 个月,直到整整 2 年),每次连续尝试都会完成,我可以 bootstrap 获得我想要的完整两年。

我怀疑这可能是由于 MySQL 服务器缓存了结果,但这似乎与文档不符:

If an identical statement is received later, the server retrieves the results from the query cache rather than parsing and executing the statement again.

http://dev.mysql.com/doc/refman/5.7/en/query-cache.html

那里的关键词似乎是 "identical," 并且我所做的其他阅读强化了查询必须相同的明显要求。 (The docs 甚至表明对查询的比较是字面的,以至于用 "SELECT" 与 "select" 编写的逻辑等效查询不匹配。)在我的例子中,每个后续查询都包含前一个查询的全部范围,但没有两个是相同的。

此外,table 会在夜间更新。因此,在昨天一天结束时,我们在 19 秒内完成了 2 年的完整查询 运行ning,据推测,它被缓存了,因为到那时我们至少获得了一次完整结果。今天不能再查询运行,这似乎与昨晚更新table时缓存已经失效一致。

所以问题是:在这种情况下是否有一些特殊情况允许服务器缓存?如果是,记录在哪里?如果没有,关于其他什么会导致此行为的任何建议?

是的,有一个缓存可以优化(一般)对硬盘的访问。它实际上是每个基于存储的数据库系统的一个非常重要的部分,因为从硬盘读取数据(或写入临时数据)通常是大多数查询最相关的瓶颈。

对于 InnoDB,这称为 InnoDB Buffer Pool:

InnoDB maintains a storage area called the buffer pool for caching data and indexes in memory. Knowing how the InnoDB buffer pool works, and taking advantage of it to keep frequently accessed data in memory, is an important aspect of MySQL tuning. For information about how the InnoDB buffer pool works, see InnoDB Buffer Pool LRU Algorithm.

You can configure the various aspects of the InnoDB buffer pool to improve performance.

  • Ideally, you set the size of the buffer pool to as large a value as practical, leaving enough memory for other processes on the server to run without excessive paging. The larger the buffer pool, the more InnoDB acts like an in-memory database, reading data from disk once and then accessing the data from memory during subsequent reads. See Section 15.6.3.2, “Configuring InnoDB Buffer Pool Size”.

可能有(并且已经)有关于 buffer pool, how it works and how to optimize it 的书籍,所以我会就此打住,只给您留下这个关键字并让您参考文档。

基本上,您的后续读取将数据添加到缓存中,这些数据可以重复使用,直到它被其他数据替换(在您的情况下发生在第二天)。由于(对于 MySQL)这可以是所涉及表的任何读取,而不必是您可能很复杂的查询,因此它可能会使您的“预取”更容易。

尽管以下带有免责声明,因为如果您更改配置,它显然会对您的服务器产生负面影响:默认 MySQL 配置非常(非常)保守,例如innodb_buffer_pool_size 系统设置对于大多数 15 岁以下的服务器来说太低了,所以也许看看你的配置(或者让你的系统管理员检查一下)。

我们做了一些实验,包括检查@Solarflare 在回答中提到的系统的效果。在我们的例子中,我们得出的结论是明显的缓存是真实的,但它与 MySQL 完全无关。它是由 Linux 磁盘缓存引起的。在我们的案例中,我们能够通过在获取结果前后手动刷新缓存并比较时间来验证这一点。