登录
注册
开源
企业版
高校版
搜索
帮助中心
使用条款
关于我们
开源
企业版
高校版
私有云
模力方舟
AI 队友
登录
注册
代码拉取完成,页面将自动刷新
Watch
不关注
关注所有动态
仅关注版本发行动态
关注但不提醒动态
3
Star
47
Fork
23
DreamCoders
/
CoderGuide
代码
Issues
1169
Pull Requests
0
Wiki
统计
流水线
服务
JavaDoc
PHPDoc
质量分析
Jenkins for Gitee
腾讯云托管
腾讯云 Serverless
悬镜安全
阿里云 SAE
Codeblitz
SBOM
开发画像分析
我知道了,不再自动展开
更新失败,请稍后重试!
移除标识
内容风险标识
本任务被
标识为内容中包含有代码安全 Bug 、隐私泄露等敏感信息,仓库外成员不可访问
MySQL一张表可以添加多少text字段?
待办的
#IAJL06
陌生人
拥有者
创建于
2024-08-13 10:10
<p style="text-align: left;">当用户从 oracle 迁移到 MySQL 时,可能由于原表字段太多建表不成功,这里讨论一个问题:一个 InnoDB 表最多能建多少个 text 字段。</p><p style="text-align: left;">我们后续的讨论基于创建表的语句形如:<span style="color: rgb(53, 148, 247); background-color: rgba(59, 170, 250, 0.1);"><code>create table t(f1 text, f2 text, …, fN text)engine=innodb;</code></span>。</p><p style="text-align: left;"><span style="color: rgb(53, 148, 247);"><strong>「默认配置」</strong></span></p><p style="text-align: left;">在默认配置下,上面的建表语句,N 取值范围为[1, 1017]。</p><p style="text-align: left;">为什么是 1017 这个“奇怪”的数字?</p><p style="text-align: left;">实际上单表的最大列数目是 1024-1,但是由于 InnoDB 会增加三个系统内部字段(主键 ID、事务ID、回滚指针),因此需要减3。而用于记录系统字典表也受 1023 的限制,又需要再增加三个该表的系统字段,因此每个表的最大字段数是 1023 - 3 * 2。</p><p style="text-align: left;"><span style="color: rgb(53, 148, 247);"><strong>「插入异常」</strong></span></p><p style="text-align: left;">上述描述说明的是表能够创建成功的最大字段数。但是这样的表是“插入不安全”的。我们知道 text 的长度上限是 64k。而往上表中插入一行,每个字段长度为 7,就会报错:<span style="color: rgb(53, 148, 247); background-color: rgba(59, 170, 250, 0.1);"><code>Row size too large (> 8126)</code></span>。</p><p style="text-align: left;">一个 page 是 16k,空 page 扣掉页信息占用空间是 16252,需要除以 2,原因是每个 page 至少要包含两个记录。</p><p style="text-align: left;">也就是说,虽然可以创建一个包含 1017 个 text 字段的表,但是很容易碰到插入失败。</p><p style="text-align: left;"><span style="color: rgb(53, 148, 247);"><strong>「如何保证插入安全」</strong></span></p><p style="text-align: left;">上面的表结构,在保证插入安全的情况下,N 的最大值是多少?</p><p style="text-align: left;">text 在存储的时候,当超过 768 字节的时候,剩余部分会保存在另外的页面(off-page),因此每个字段占用的最大空间为 768 + 20 + 2 = 788. 20 字节存储最短剩余部分的位置(SPACEID+PAGEID+OFFSET)。2 字节存储本地实际长度。</p><p style="text-align: left;">因此 N 最大值为 lower(8126 / 790) = 10。</p><p style="text-align: left;">如果我们想在创建的表的时候,保证创建的表中的 text 字段都能安全的达到 64k 上限(而不是等插入的时候才发现),那么需要将默认为 OFF 的 innodb_strict_mode 设置为 ON,这样在建表时会先做判断。</p><p style="text-align: left;">但是,在设置为严格模式后,上述建表语句的最大 N 却并非 10。</p><h5 style="text-align: left;"><span style="color: rgb(64, 184, 250);">ROW_FORMAT</span></h5><p style="text-align: left;">在 off-page 存储时,本地占用790个字节,是基于默认的 ROW_FORMAT,即为 COMPACT,此时插入安全的 N 上限为 10。</p><p style="text-align: left;">而在 InnoDB 新格式 Barracuda 支持下,Dynamic 格式的 off-page 存储时,在 local 保存的上限不再是 768,而是 20 个字节。这样每个字段在数据页里面占用的最大值是 40byte,再需要一个额外的字节存储实际的本地长度,因此每个 text 最大占用 41 字节。</p><p style="text-align: left;">实际上很容易测试在严格模式下,建表的最大 N 为 196。以下为 N=197 时计算过程:</p><ul><li style="text-align: left;">每行记录预留header 5个字节。</li><li style="text-align: left;">每个bit保存是否允许null,需要 upper(197/8)=25个字节。</li><li style="text-align: left;">三个系统保留字段 6+6+7=19.</li></ul><p style="text-align: left;">因此总占用空间:5+25+19+41*197=8126!</p><p style="text-align: left;">也就是说,当 N=197 时,刚好长度为 8126,而代码中实现是<span style="color: rgb(53, 148, 247); background-color: rgba(59, 170, 250, 0.1);"><code>if(rec_max_size >= page_rec_max) reutrn(error)</code></span>。</p><p style="text-align: left;">就这么不巧!</p><h5 style="text-align: left;"><span style="color: rgb(64, 184, 250);">作为补充</span></h5><p style="text-align: left;">有经验的读者可以联想到,如果我们的表中自己定义一个 int 型主键呢?此时系统不需要额外增加主键,因此整个表结构比之前少 2 字节。</p><p style="text-align: left;">也就是说,建表语句修改为: <span style="color: rgb(53, 148, 247); background-color: rgba(59, 170, 250, 0.1);"><code>create table t(id int primary key, f1 text, f2 text, …, fN text)engine=innodb;</code></span>。</p><p style="text-align: left;">则此时的 N 上限能达到 197。</p>
<p style="text-align: left;">当用户从 oracle 迁移到 MySQL 时,可能由于原表字段太多建表不成功,这里讨论一个问题:一个 InnoDB 表最多能建多少个 text 字段。</p><p style="text-align: left;">我们后续的讨论基于创建表的语句形如:<span style="color: rgb(53, 148, 247); background-color: rgba(59, 170, 250, 0.1);"><code>create table t(f1 text, f2 text, …, fN text)engine=innodb;</code></span>。</p><p style="text-align: left;"><span style="color: rgb(53, 148, 247);"><strong>「默认配置」</strong></span></p><p style="text-align: left;">在默认配置下,上面的建表语句,N 取值范围为[1, 1017]。</p><p style="text-align: left;">为什么是 1017 这个“奇怪”的数字?</p><p style="text-align: left;">实际上单表的最大列数目是 1024-1,但是由于 InnoDB 会增加三个系统内部字段(主键 ID、事务ID、回滚指针),因此需要减3。而用于记录系统字典表也受 1023 的限制,又需要再增加三个该表的系统字段,因此每个表的最大字段数是 1023 - 3 * 2。</p><p style="text-align: left;"><span style="color: rgb(53, 148, 247);"><strong>「插入异常」</strong></span></p><p style="text-align: left;">上述描述说明的是表能够创建成功的最大字段数。但是这样的表是“插入不安全”的。我们知道 text 的长度上限是 64k。而往上表中插入一行,每个字段长度为 7,就会报错:<span style="color: rgb(53, 148, 247); background-color: rgba(59, 170, 250, 0.1);"><code>Row size too large (> 8126)</code></span>。</p><p style="text-align: left;">一个 page 是 16k,空 page 扣掉页信息占用空间是 16252,需要除以 2,原因是每个 page 至少要包含两个记录。</p><p style="text-align: left;">也就是说,虽然可以创建一个包含 1017 个 text 字段的表,但是很容易碰到插入失败。</p><p style="text-align: left;"><span style="color: rgb(53, 148, 247);"><strong>「如何保证插入安全」</strong></span></p><p style="text-align: left;">上面的表结构,在保证插入安全的情况下,N 的最大值是多少?</p><p style="text-align: left;">text 在存储的时候,当超过 768 字节的时候,剩余部分会保存在另外的页面(off-page),因此每个字段占用的最大空间为 768 + 20 + 2 = 788. 20 字节存储最短剩余部分的位置(SPACEID+PAGEID+OFFSET)。2 字节存储本地实际长度。</p><p style="text-align: left;">因此 N 最大值为 lower(8126 / 790) = 10。</p><p style="text-align: left;">如果我们想在创建的表的时候,保证创建的表中的 text 字段都能安全的达到 64k 上限(而不是等插入的时候才发现),那么需要将默认为 OFF 的 innodb_strict_mode 设置为 ON,这样在建表时会先做判断。</p><p style="text-align: left;">但是,在设置为严格模式后,上述建表语句的最大 N 却并非 10。</p><h5 style="text-align: left;"><span style="color: rgb(64, 184, 250);">ROW_FORMAT</span></h5><p style="text-align: left;">在 off-page 存储时,本地占用790个字节,是基于默认的 ROW_FORMAT,即为 COMPACT,此时插入安全的 N 上限为 10。</p><p style="text-align: left;">而在 InnoDB 新格式 Barracuda 支持下,Dynamic 格式的 off-page 存储时,在 local 保存的上限不再是 768,而是 20 个字节。这样每个字段在数据页里面占用的最大值是 40byte,再需要一个额外的字节存储实际的本地长度,因此每个 text 最大占用 41 字节。</p><p style="text-align: left;">实际上很容易测试在严格模式下,建表的最大 N 为 196。以下为 N=197 时计算过程:</p><ul><li style="text-align: left;">每行记录预留header 5个字节。</li><li style="text-align: left;">每个bit保存是否允许null,需要 upper(197/8)=25个字节。</li><li style="text-align: left;">三个系统保留字段 6+6+7=19.</li></ul><p style="text-align: left;">因此总占用空间:5+25+19+41*197=8126!</p><p style="text-align: left;">也就是说,当 N=197 时,刚好长度为 8126,而代码中实现是<span style="color: rgb(53, 148, 247); background-color: rgba(59, 170, 250, 0.1);"><code>if(rec_max_size >= page_rec_max) reutrn(error)</code></span>。</p><p style="text-align: left;">就这么不巧!</p><h5 style="text-align: left;"><span style="color: rgb(64, 184, 250);">作为补充</span></h5><p style="text-align: left;">有经验的读者可以联想到,如果我们的表中自己定义一个 int 型主键呢?此时系统不需要额外增加主键,因此整个表结构比之前少 2 字节。</p><p style="text-align: left;">也就是说,建表语句修改为: <span style="color: rgb(53, 148, 247); background-color: rgba(59, 170, 250, 0.1);"><code>create table t(id int primary key, f1 text, f2 text, …, fN text)engine=innodb;</code></span>。</p><p style="text-align: left;">则此时的 N 上限能达到 197。</p>
评论 (
0
)
登录
后才可以发表评论
状态
待办的
待办的
进行中
已完成
已关闭
负责人
未设置
标签
MySql
未设置
标签管理
里程碑
未关联里程碑
未关联里程碑
Pull Requests
未关联
未关联
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
未关联
分支 (
-
)
标签 (
-
)
开始日期   -   截止日期
-
置顶选项
不置顶
置顶等级:高
置顶等级:中
置顶等级:低
优先级
不指定
严重
主要
次要
不重要
参与者(1)
1
https://gitee.com/DreamCoders/CoderGuide.git
git@gitee.com:DreamCoders/CoderGuide.git
DreamCoders
CoderGuide
CoderGuide
点此查找更多帮助
搜索帮助
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
评论
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册