当您使用更长的字符串更新 VARCHAR 单元格时会发生什么?

Mah*_*koe 5 mysql varchar update

VARCHAR(32)假设我在 mySQL 数据库中有一个类型的列。

9 月 1 日,我决定存储该字符串"tea",但 9 月 2 日,我决定将其更新为"coffee".

显然,如果该表中的所有记录都相互挤压,并且我们尝试将一条记录加长 3 个字节,那么该记录之后出现的所有记录都需要向下移动 3 个字节。当然,这是荒谬的;任何 DBMS 都不可能转移数千个可能的条目。

那么mySQL 在这种情况下到底会做什么呢?对于 TEXT 和 BLOB 类型,它的行为方式是否相同?

编辑: 一天后读完这篇文章后,我意识到这个问题相当模糊。这是一个我希望能够澄清问题的例子:

假设我有一个表,fav_drinks有两列:

  • user_id,这是一个INTEGER
  • drink,这是一个VARCHAR(32)

假设这个表在内存中是这样存储的:

[1,"juice",2,"tea",3,"soda",4,"hot chocolate"]
Run Code Online (Sandbox Code Playgroud)

也就是说,所有记录都按顺序存储。如果我们需要将用户 2 最喜欢的饮料从 更新为"tea""coffee"理论上我们需要将用户 3 和 4 的条目下移。当然,我不认为这在真实的数据库中会发生。

那么,重申一下这个问题,mySQL 如何管理一个表条目突然需要更多内存的这种特定情况?

Ric*_*mes 5

MySQL 的 InnoDB 将行存储在每个 16KB 的块中。在一个区块内,可能有几行大行,也可能有数百行窄行。街区中几乎总会有一些空闲空间。当行中的列发生更改时,该行将在同一个块中重写(如果可能),并且块内的内容会被打乱以腾出空间。(确切的细节隐藏在代码中。)

如果添加了太多文本(或斑点或其他内容),导致块中没有空间,则出现“块分割”。这是原始块中的行被分成两个块的地方。

块存储在块的 B+Tree 排列中。(参见维基百科。)因此,块不一定是连续存储的,但可以连续引用。因此,十亿行表中的块拆分与一百行表中的块拆分的工作量大致相同。

另一个方面是“MVCC”,它允许多个事务同时接触相同的行。这不仅会导致用修改后的值替换行,而且实际上会保留该行的前一个副本,直到需要它的事务完成为止。但同样,块中的空闲空间,加上块分裂,加上 BTree 组织来处理这个问题。

那么,您的下一个问题是关于删除吗?好吧,如果文本缩小了很多,或者一堆行缩小了DELETEd,那么看起来一个块可能会缩小很多,甚至可能被清空?是的。在这种情况下,InnoDB 检查两个相邻块是否小到足以合并,并执行此操作,从而释放其中一个块以供将来使用。(这个释放的块保留在表空间中,不会返回给操作系统,因此 ibdata1 永远不会收缩;等等)

所有这些事情都发生在幕后,我们不需要担心。

非常大的记录:例如,一行和一MEDIUMTEXT列包含 1MB 数据,16KB 无法容纳。该怎么办?嗯,庞大的列实际上存储在其他块中,与记录的主要部分分开。这会导致行的最大大小出现一些令人困惑的限制以及一些意外的性能问题。同样,这是透明处理的,分配单位是 16KB。

当我这样做时,请注意 an 的结构INDEX本质上与表的结构相同 - 一个 16KB 块的 BTree,当为行插入/删除添加/删除索引条目时,它在幕后玩块拆分/合并游戏。


归档时间:

查看次数:

1109 次

最近记录:

8 年,2 月 前