MySQL深入——23

主机内存只有100G,现在对一个200G的大表进行扫描,会不会把数据库的内存用完。

对大表做全表扫描对Sever层的影响

假设现对一个200G的InnoDB表db1,做一个全表扫描,当然要把扫描结果保存到客户端。

InnoDB的数据时保存在主键索引上的,所以全表扫描实际上是扫描表t的主键索引,最后返回给客户端。

返回的结果集并不是完整的,因为MySQL是边读边发的
流程为:1.获取一行写到net_buffer当中,net_buffer是由net_buffer_length定义的,默认为16k。

               2.重复获取知道net_buffer写满,调用网络接口发送出去。

               3.若是发送成功,就清空net_buffer,然后继续读取下一行写入net_buffer

               4.若发送函数返回EAGAIN或WSAEWOULDBLOCK就表示本地网络栈写满,直到网络栈重写可写,再继续重复操作。

一个查询在发送过程当中,占用MySQL内部最大内存就是net_buffer这么大,并不会达到200G。这意味着,若客户端接收慢,MySQL就会由于结果发送不出去导致事务执行的时间变长。

若是客户端不读socket receive buffer中的内容,然后再show processlist中可以看到state处于一个Sending to client的状态。

对于线上业务来说,若是一个查询的返回结果不会很多,就可以在客户端使用一个-quick参数就可以使用,mysql_use_result这个方法,读一行处理一行。当然前提是查询返回结果不多,若是看到多个线程都处于Sending to client,可以将net_buffer_length设置为一个更大的值。

Sending data

MySQL查询语句在进入执行阶段之后,首先将状态设置为Sending data,再继续执行语句的流程,执行完成后就会将状态改为空字符串。

也就是说在一个线程处于“等待客户端的状态”才会显示未Sending to client,Sending data是正在执行。

全表扫描对InnoDB的影响

InnoDB内存的作用是保持更新结果在配合redo log避免了随机写盘,内存的数据页是在BUffer Pool中管理的。

BUffer Pool还有一个加速功能,因为有WAL机制,当时事务要提交的时候,有一个查询要读该内存页,就可以直接读,因为这个时候,内存页是最新的,直接读内存页就可以了,无需将redo log应用到数据页当中再读取。

Buffer Pool对于查询加速效果还有一个重要的指标:内存命中率,一般情况下,内存命中率要在99%以上。

InnoDB Buffer Pool大小是由参数innodb_buffer_pool_size决定的,一般设置为物理内存的60%-80%。

innodb_buffer_pool_size小于磁盘的数据量很常见,若一个buffer pool满了,就要淘汰一个旧数据页来更新一个新数据页。InnoDB通过改进LRU算法来实现这一目标。

LRU算法:假设内存当中有P1,P2,P3,P4,P5这么多数据页,是以链表形式保存的,P1是刚刚更新的所以在头部,这个时候有请求访问P3,P3就会被移动到头部,现在要更新一个数据页,因为内存满了,要删除一个,就会删除尾巴的P5数据页。

InnoDB改进:InnoDB将其进行改进,以5:3将空间分为young和old区域,young区域中的操作和原LRU算法相同。

在old区域每次被访问的时候做如下的操作:

1.若这个数据页在LRU链表中存在时间超过1秒,就移动到头部。

2.若是短于1秒,位置保持不变

时间有参数Innodb_old_blacks_time控制,单位为毫秒,默认一秒。

  • 21
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 确实,MySQL的varchar类型在InnoDB存储引擎中的存储结构比较复杂。在InnoDB中,每个记录都被存储为一个B+树节点,每个节点都有一个固定大小的页,通常为16KB。 当一个varchar类型的列被插入到InnoDB表中时,它会被拆分成两个部分:一个是实际的数据,另一个是长度信息。长度信息会被存储在记录头中,而实际的数据会被存储在记录的数据页中。 在InnoDB中,如果一个varchar类型的列的长度小于等于768个字节,那么它会被存储在记录的数据页中。如果一个varchar类型的列的长度超过了768个字节,那么它会被存储在单独的页中,并且在记录中只存储一个指向这个页的指针。 此外,由于InnoDB使用了行级锁定,每个记录都需要存储一个事务ID,用于实现MVCC(多版本并发控制)。因此,在InnoDB中,每个记录头还需要存储一个6字节的事务ID和一个2字节的回滚指针。 综上所述,当使用varchar类型时,需要注意其实际数据的长度和存储引擎的存储结构,以便更好地设计表结构和查询语句。 ### 回答2: MySQL的varchar存储结构确实是相当深奥的。在InnoDB存储引擎中,varchar类型的数据存储在表的记录中,其存储结构会影响数据写入、存储空间占用和查询性能。 首先,varchar类型的数据在记录中是以变长字符串的形式进行存储的。这意味着,varchar字段占用的存储空间与其实际存储的数据长度相关,而不是固定的。相比之下,固定长度的数据类型(如char)在存储时会占用固定的存储空间,无论实际数据的长度是多少。 其次,varchar类型的数据在记录中的存储格式是由一个表示长度的字节和真实字符串数据构成的。这个长度字段用于指示存储的实际数据的长度,使得数据库可以根据需要动态地分配存储空间,从而节省了存储空间。 此外,在InnoDB存储引擎中,varchar字段的数据存储在页内部的某个位置,而不是直接存储在页上。这是由于InnoDB采用了B+树的数据结构来组织数据,为了节省存储空间和提高数据访问效率,varchar字段的数据会被存储在叶子节点中。这样一来,在查询时可以更快地遍历和定位数据,提高查询性能。 综上所述,MySQL的varchar存储结构的深度体现在其变长存储方式、长度字段和数据存储位置等方面。了解和理解这些存储结构对于正确使用varchar类型的字段、优化存储空间和提高查询性能都是非常重要的。 ### 回答3: MySQL的varchar存储结构在InnoDB引擎中确实是一个很深入的话题。InnoDB引擎是MySQL的默认引擎,它采用了B+树索引来存储数据。在InnoDB的记录存储结构中,varchar类型字段经过了一系列处理。 首先,InnoDB将每个记录分为固定长度部分和变长长度部分。varchar字段属于变长长度部分。对于varchar字段,MySQL会额外存储一个指针,指向数据存储区域。 其次,在实际存储varchar字段值时,InnoDB会使用两种方式。对于较短的varchar字段值,会直接将其存储在记录的数据域中。这样做的好处是可以减少额外的存储开销。 而对于较长的varchar字段值,InnoDB会将其存储在一个称为“Overflow Page”的额外存储空间中。Overflow Page的指针存储在记录的数据域中。Overflow Page与主记录有一个单独的物理连接。 另外,需要注意的是,在InnoDB中,varchar字段的长度是可变的,存储的最大长度由定义时的最大长度决定。这与char字段是不同的,char字段的长度是固定的。 总之,MySQL的varchar存储结构在InnoDB引擎中是相对复杂的。它采用了不同的存储方式来处理不同长度的字段值,既保证了数据的存储效率,又满足了灵活性的要求。对于开发人员来说,了解varchar存储结构对于正确使用和优化数据库非常重要。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

下水道程序员

你的鼓励将是我奋斗的最大动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值