mysql执行SQL时如何读取数据_mysql数据存取流程

来源:这里教程网 时间:2026-02-28 20:47:33 作者:

MySQL执行SELECT时数据从哪来

MySQL读取数据不是直接从磁盘文件里逐行扒,而是优先走缓冲池(Buffer Pool)。只要查询的页(page)已在

innodb_buffer_pool
中,就直接内存返回;没命中才触发物理读,把对应16KB的数据页从
.ibd
文件加载进内存。

注意:即使表很小、只有一行,也必须按页为单位加载——不会跳过页结构去“读一行”。所以

SELECT * FROM t WHERE id = 1
仍可能引发一次逻辑读(buffer pool lookup),甚至一次物理读(disk I/O)。

为什么EXPLAIN显示type=ALL却没扫全表

type=ALL
只表示没用上索引做查找,但不等于真把每行都读一遍。InnoDB实际读取范围取决于:
WHERE
条件是否能利用隐式下推、是否被优化器提前剪枝、以及MVCC版本链是否跳过大量旧版本行。

如果表有200万行,但
WHERE status = 'active'
只匹配100行,且
status
无索引,InnoDB仍要遍历所有聚簇索引页,但每页内只检查满足条件的记录——不是每行都解包、不是每行都构造完整结果集
若事务隔离级别是
REPEATABLE READ
,还要沿着undo日志链判断可见性,这部分开销不体现在
rows_examined
Handler_read_next
状态变量比
Rows_examined
更贴近真实数据访问次数,可用
SHOW STATUS LIKE 'Handler%'
查看

SELECT过程中哪些环节会阻塞写入

InnoDB对读操作本身几乎不加锁(快照读),但某些场景仍会间接影响写入性能:

大范围
SELECT ... FOR UPDATE
SELECT ... LOCK IN SHARE MODE
会持有记录锁或间隙锁,阻塞并发DML
全表扫描类查询若持续时间长,会延长
dict_table_t::n_rec_locks
统计周期,增加元数据锁(MDL)争用,卡住
ALTER TABLE
Buffer Pool被大量只读查询占满,导致后续UPDATE/INSERT所需的脏页刷盘延迟上升,间接拖慢写入吞吐

数据从磁盘到客户端经历了几层拷贝

典型路径:磁盘文件 → OS Page Cache → InnoDB Buffer Pool → MySQL Server内存临时结构(如

JOIN
中间结果)→ 网络发送缓冲区 → 客户端socket接收缓冲区。

关键点:

Linux默认启用
innodb_use_native_aio=ON
,异步IO可减少线程等待,但若磁盘是机械盘或队列深度低,反而增加延迟
net_buffer_length
max_allowed_packet
决定了Server层每次组装多少行再发给网络栈;太小会导致频繁系统调用,太大可能触发TCP分片或OOM
客户端fetch行为影响极大:Python的
cursor.fetchall()
是一次性拉完,而
fetchone()
配合循环才是流式读取,避免Server端缓存整张结果集

真正耗时的往往不在SQL解析,而在数据在各层间搬运和序列化——尤其是大字段(

TEXT
/
BLOB
)未设置
NO_CACHE
提示时,会被反复复制多次。

相关推荐