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

1次阅读

mysql读取数据优先从InnoDB缓冲池(Buffer Pool)获取,未命中时才从.ibd文件加载16KB数据页;即使单行查询也按页加载,可能触发逻辑读或物理读。

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

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 UPDATESELECT ... 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_lengthmax_allowed_packet决定了Server层每次组装多少行再发给网络;太小会导致频繁系统调用,太大可能触发TCP分片或OOM
  • 客户端fetch行为影响极大:pythoncursor.fetchall()是一次性拉完,而fetchone()配合循环才是流式读取,避免Server端缓存整张结果集

真正耗时的往往不在SQL解析,而在数据在各层间搬运和序列化——尤其是大字段(TEXT/BLOB)未设置NO_CACHE提示时,会被反复复制多次。

text=ZqhQzanResources