31

我正在尝试对不同列上的不同查询进行一些基准测试,但 MySQL 不允许我这样做。在第一次执行查询后,我再也无法为该查询获得相同的执行时间。例如,如果查询第一次在 0.062 秒内执行,我永远无法在第二次、第三次等运行中获得相同的执行时间。它变为 0 秒或类似 0.015。

我已经阅读了许多关于禁用和清除 MySQL 查询缓存的帖子,但没有一篇对我有任何帮助。

像这样的帖子在这里

无论我做什么,MySQL 似乎都坚持使用缓存结果。

我重新启动 MySQL Workbench,然后运行;

set global query_cache_type=0;
set global query_cache_size=0;
flush query cache;
reset query cache;

执行时间一直显示 0 秒。

只有我无法更改的服务器变量是“have_query_cache”。它的值为“是”,当我尝试将其设置为“否”时,Workbench 说它是只读的。

我也这样做;

set profiling=1;
run my select query
show profile for query 2;

分析结果表明:

'starting', '0.000077'
'checking permissions', '0.000007'
'Opening tables', '0.000016'
'init', '0.000035'
'System lock', '0.000009'
'optimizing', '0.000013'
'statistics', '0.000094'
'preparing', '0.000008'
'executing', '0.000002'
'Sending data', '0.000016'
'end', '0.000002'
'query end', '0.000003'
'closing tables', '0.000005'
'freeing items', '0.000139'
'cleaning up', '0.000009'

如果我没有错,这表明没有使用缓存对吗?但我仍然看到 0 秒。为执行时间。

编辑:我正在运行的查询是使用“SQL_NO_CACHE”的 SELECT 查询,如下所示:

SELECT SQL_NO_CACHE col1,now() from mytable where col2="some_value"

(我添加了 now() 函数来帮助我防止查询缓存)

Edit2:我正在使用 innoDB,MySQL 5.6.10

有人可以帮助我,因为我看不到这里发生了什么。

非常感谢!

4

5 回答 5

29

这可能是由于数据本身的缓存,而不是查询缓存。

为了确保这一点,您可以通过在SELECT语句后添加SQL_NO_CACHE来禁用单个语句的查询缓存。

前任:

SELECT SQL_NO_CACHE field FROM table.

于 2013-04-16T18:06:44.347 回答
10

第一次运行查询会使InnoDB缓冲池填充表的相关块。

由于重新运行查询需要完全相同的块,因此它使查询无需在重新运行时从磁盘读取它们,从而显着加快速度。

于 2013-04-16T18:07:49.630 回答
7

您可以验证缓冲池页面读取与必须进入磁盘才能获取页面的页面读取之间的区别:

mysql> SHOW SESSION STATUS LIKE 'Innodb_buffer_pool_read%';
mysql> ...run a query...
mysql> SHOW SESSION STATUS LIKE 'Innodb_buffer_pool_read%';

比较报告中的这些值,并注意它们增长了多少:

+---------------------------------------+----------+
| Variable_name                         | Value    |
+---------------------------------------+----------+
| Innodb_buffer_pool_read_requests      | 10327490 |
| Innodb_buffer_pool_reads              | 1133     |
+---------------------------------------+----------+

read_requests是逻辑页面读取,它可能从缓冲池中已经存在的页面中读取如果这个数字在您的查询后增长,但读取数没有增长,那么您的查询仅从缓冲池中获取结果。

读取是必须输出到磁盘的页面读取次数,并且会产生 I/O 成本以将页面复制到缓冲池中。如果查询后这个数字增加,那么它必须从磁盘加载数据。

有关内存访问与磁盘访问性能之间差异的更多信息,请阅读http://everythingisdata.wordpress.com/2009/10/17/numbers-everyone-should-know/


回复您的评论:

“打开表”与 InnoDB 表的内存缓存有关,有点像数据字典。表在重新启动后第一次被引用时打开。内存数据字典中给定表的条目无限期地保留在内存中,因此如果您有数千个表,内存使用量可能会变得非常大。在 MySQL 5.6 中,他们有一些调整变量来限制内存使用,并驱逐不经常使用的表。但整个机制与缓冲池是分开的,缓冲池存储数据页和索引。

“统计”也与缓冲池分开。InnoDB 维护有关数据和索引的内存统计信息,用于指导查询优化器。当您第一次访问 InnoDB 表时,当您运行 SHOW TABLE STATUS 或针对 INFORMATION_SCHEMA 运行某些查询时,当您运行 ANALYZE TABLE 时,以及当表的大小发生显着变化时,统计信息会自动刷新。InnoDB 生成这些统计信息,随机从表中读取固定数量的页面,如果您有冷缓冲池,这很可能会影响磁盘。

于 2013-04-17T00:11:23.773 回答
4

好的。所以我一直在研究这个 innoDB 缓冲池问题。谢谢@Quassnoi,@TheVedge 提到这一点。它对以下工作非常有用。

我试图找到一种方法来禁用或重置 innoDB 缓冲池,但除了重新启动 MySQL 服务器之外,我找不到其他方法。(要在 Windows 框中重新启动服务器,您可以使用 services.msc 或命令提示符。)

我猜所有的配置变量设置和“SQL_NO_CACHE”的使用足以避免使用缓存,并且检查分析结果我也没有看到任何缓存引用(检查原始帖子)。

然后我决定在重新启动 MySQL 服务器后检查相同查询的第 1 次和第 2 次运行的分析。这样我就可以一步一步地看到查询执行过程中发生了什么。

服务器重新启动后的第一次运行产生了以下步骤和时间:

'starting', '0.000078'
'checking permissions', '0.000005'
'Opening tables', '0.120329'
'init', '0.000107'
'System lock', '0.000012'
'optimizing', '0.000024'
'statistics', '0.065317'
'preparing', '0.000026'
'executing', '0.000003'
'Sending data', '0.000038'
'end', '0.000005'
'query end', '0.000006'
'closing tables', '0.000014'
'freeing items', '0.000463'
'cleaning up', '0.000039'

这些是第二次运行的结果:

'starting', '0.000068'
'checking permissions', '0.000006'
'Opening tables', '0.000019'
'init', '0.000046'
'System lock', '0.000007'
'optimizing', '0.000010'
'statistics', '0.000073'
'preparing', '0.000009'
'executing', '0.000002'
'Sending data', '0.000035'
'end', '0.000003'
'query end', '0.000003'
'closing tables', '0.000006'
'freeing items', '0.000181'
'cleaning up', '0.000015'

如您所见,两次执行之间的“打开表”和“统计”操作的持续时间存在巨大差异,并且没有任何执行引用任何缓存。

这两个动作似乎是第一次执行最耗时的部分(我相信这是创建 innoDB 缓冲池的一部分),并且一旦生成池,这两个动作就不会那么频繁地执行,因此执行时间要短得多缓冲池创建后的查询。

当您总结第二次运行的各个步骤的执行时间时,我们得到 0.000483 秒,我认为 MySQL 工作台将此结果显示为 0.000 秒,这也可能会让您认为第二次运行是缓存使用的结果,但实际上看起来像它不是。这只是查询执行持续时间的显示精度问题。

结果,到目前为止,我发现我实际上已经能够禁用缓存的使用,并且是 innoDB 缓冲池的完成大大加快了第二个查询的速度。这也意味着我可以在 0.000483 秒内找到 200 万行的记录。

你会同意吗?

于 2013-04-16T22:42:12.387 回答
1

在 [mysqld] 部分的 .ini/.cfg 中,添加一行have_query_cache=0 # to prevent using resources from default of yes ccyy/mm/dd your initials. 使用您的其他更改,关闭/重新启动 MySQL。您不应在概况研究中观察任何 QC 活动。

于 2017-08-24T12:21:20.900 回答