SQL_NO_CACHE仅对已废弃的查询缓存有效,MySQL 8.0已彻底移除,5.7默认禁用且常被编译裁剪;它不作用于InnoDB缓冲池、OS页缓存等真正影响磁盘读取的层级,加了也会被静默忽略。

SQL_NO_CACHE 不能强制查询不使用 InnoDB 缓冲池(即“InnoDB缓存”),它只对早已废弃的查询缓存(query cache)起作用。在 MySQL 8.0 中该功能已被彻底移除,5.7 默认禁用且编译时经常被裁掉;你加了 SQL_NO_CACHE,MySQL 会静默忽略,既不报错也不生效。
SQL_NO_CACHE 在哪些版本里还“存在”但基本无效
仅限 MySQL 5.6 或更早、且满足以下全部条件的极少数遗留环境:
-
have_query_cache = YES(编译时启用了查询缓存) -
query_cache_type = 1(全局开启)且query_cache_size > 0 - 查询是确定性的(不能含
NOW()、USER()、子查询带非确定函数等) - 执行期间表没发生任何写操作(否则缓存条目会被自动清空)
即便满足,SQL_NO_CACHE 也只阻止结果写入查询缓存,不影响 InnoDB 缓冲池、OS 页缓存、客户端连接层缓存——这些才是真正决定“是否读磁盘”的层级。
为什么 SHOW STATUS LIKE 'Qcache_hits' 始终为 0
这是最直接的信号:查询缓存根本没在工作。常见原因包括:
- MySQL 8.0+:系统变量
query_cache_type已被删除,执行SHOW VARIABLES LIKE 'query_cache_type'会报错Unknown system variable 'query_cache_type' - MySQL 5.7:默认
query_cache_type = OFF,且很多发行版(如官方 Docker 镜像、Percona、阿里云 RDS)编译时传了--without-query-cache - 即使
have_query_cache = YES,若query_cache_size = 0,缓存区为零,缓存逻辑不会触发
此时加 SQL_NO_CACHE 就像给一辆没油的车挂空挡——动作做了,但底层没响应。
真正影响“是否读磁盘”的是哪几层,怎么动
想让某次 SELECT 更大概率走物理 IO(而非缓冲池或 OS 缓存),得干预 InnoDB 缓冲池和操作系统页缓存:
- 清空目标表相关页:执行
SELECT COUNT(*) FROM t FORCE INDEX (PRIMARY) WHERE id BETWEEN ? AND ?(范围足够大,把热点页挤出缓冲池),比直接调小innodb_buffer_pool_size更安全、无需 SUPER 权限 - 绕过 OS 缓存(仅限 Linux 测试环境):
sudo sh -c "echo 3 > /proc/sys/vm/drop_caches",但这是全局操作,会清空所有文件缓存,生产环境严禁使用 - InnoDB 缓冲池级控制不可通过 SQL 完成:没有类似
SQL_NO_BUFFER_POOL的语法;innodb_buffer_pool_dump_now/load_now是用于持久化快照,不是绕过
注意:即使做了上述操作,InnoDB 仍可能因 MVCC 版本链、change buffer 合并等机制触发逻辑读,所谓“强制读磁盘”在实际中只能趋近,无法 100% 保证。
真正要测单条查询的原始磁盘延迟,得结合 EXPLAIN FORMAT=JSON 看 handler_read_* 状态、用 perf record -e block:block_rq_issue 抓块设备请求,再对照 innodb_buffer_pool_pages_data 等状态变量交叉验证——SQL_NO_CACHE 连门都没摸到。











