草庐IT

MySql 数据类型所占存储空间

鱼蛮子9527 2023-03-28 原文

最近在折腾指标监控报警,对指标监控来说,海量的数据存储肯定是考验,业内比较好的方案应该是存储到时序数据库。对我们来说刚开始起步,存储到最熟悉的 MySql 肯定是最快最稳妥的方案。做啥都是应该先跑起来,一下子吃成胖子很容易撑坏。做大做强,再创辉煌,应该是取得一定成绩后的目标。

虽说初期小业务量,但是对最基本的存储来说,还是应该能省就省。现在外部大环境不好,集团也特别关注成本的控制。放到程序上来说,每行更小的数据 size,意味着数据读取的更块,系统跑的更快。

所以就整体复习了下 MySql 各种字段的存储需求,MySql 版本是 5.7。

总体说明

表数据在磁盘上的存储取决于几个因素,不同的存储引擎表示数据类型及对原始数据的存储都是不同的。表数据可能会被压缩,无论是针对一列还是整行,这会使表或列的存储需求计算复杂化。我们就不去关注其他引擎了,都是基于 InnoDB 引擎。

在数据库内部,表中的行大小最大为 65,535 字节,即使存储引擎能够支持更大的行。这个数字排除了 BLOB 或 TEXT 列,它们只占这个大小的 9 到 12 个字节。对于 BLOB 和 TEXT 数据,信息存储在与行缓冲区不同的内存区域中。不同的存储引擎根据它们处理相应类型的方法,以不同的方式处理这些数据的分配和存储。

数值类型

数据类型 存储要求 数据范围
TINYINT 1 byte -128 到 127
SMALLINT 2 bytes -32768 到 32767
MEDIUMINT 3 bytes -8388608 到 8388607
INT, INTEGER 4 bytes -2147483648 到 2147483647
BIGINT 8 bytes -9223372036854775808 到 9223372036854775807
FLOAT(p) 当 0 <= p <= 24 , 4 bytes
当 25 <= p <= 53 , 8 bytes
FLOAT 4 bytes -3.402823466E+38 到 -1.175494351E-38
0
1.175494351E-38 到 3.402823466E+38.
DOUBLE [PRECISION], REAL 8 bytes -1.7976931348623157E+308 到 -2.2250738585072014E-308
0
2.2250738585072014E-308 到 1.7976931348623157E+308.
DECIMAL(M,D), NUMERIC(M,D) 请看:DECIMAL 特殊说明 M 长度最大为 65
BIT(M) 约为 (M+7)/8 bytes M 长度 1 到 64

DECIMAL

在MySQL中,NUMERIC 是作为 DECIMAL 实现的,所以下面所有 DECIMAL 的说明同样适用于 NUMERIC。

DECIMAL 类型的值使用二进制格式表示,将 9 个十进制数字装入 4 个字节。每个值的整数和小数部分的存储是单独确定的。每 9 位数就需要 4 个字节,而 "剩余 "的数字需要至少 4 个字节来存储。多余的数字所需的存储量由下表中给出。

剩余数字个数 存储需求
0 0 bytes
1, 2 1 byte
3, 4 2 bytes
5, 6 3 bytes
7, 8 4 bytes

可以看出奇数个位数跟 +1 后的偶数位数所需的空间是一样的,如果只考虑存储成本,我们在使用的时候,可以尽量让剩余数字个数为偶数值。

在标准 SQL 中,DECIMAL(M) 的语法等同于 DECIMAL(M,0)。类似地,DECIMAL 语法等同于 DECIMAL(M,0),其中允许执行者决定 M 的值。M 的默认值是10。

DECIMAL 的最大位数是 65,但是一个给定的 DECIMAL 列的实际范围会受到给定列的精度或比例的限制。当这样的一列被分配到一个小数点后面的数字多于指定比例所允许的数值时,该数值将被转换为该比例。(精确的行为是由操作系统决定的,但通常的效果是截断到允许的位数)。

日期和时间类型

数据类型 存储需求
YEAR 1 byte
DATE 3 bytes
TIME 3 bytes + 小数秒存储
DATETIME 5 bytes + 小数秒存储
TIMESTAMP 4 bytes + 小数秒存储

从 MySQL 5.6.4 开始,对 TIME、DATETIME 和 TIMESTAMP 改为固定大小 + 小数秒存储方式,需要 0 到 3 个字节,这取决于存储的小数秒值精度。

小数秒精度 存储需求
0 0 bytes
1, 2 1 byte
3, 4 2 bytes
5, 6 3 bytes

可以看到与 DECIMAL 类似,如果只考虑存储成本,我们在使用的时候,可以尽量设置成所需的偶数值。

例如,DATETIME(0)、DATETIME(2)、DATETIME(4) 和 DATETIME(6) 分别使用 5、6、7 和 8 个字节。DATETIME 和 DATETIME(0) 是等价的,需要相同的存储空间。

字符串类型

可变长度字符串类型使用长度前缀加数据存储。根据数据类型,长度前缀需要 1 到 4 个字节,字符串的字节长度为 L。例如,存储一个 MEDIUMTEXT 值需要 L 个字节来存储该值,再加上 3 个字节来存储该值的长度。

在下表中,M 表示非二进制字符串类型的声明列长度(以字符为单位)和二进制字符串类型的字节数。 L 表示给定字符串值的实际长度(以字节为单位),特别注意,这里不是字符长度,开始时候很容易弄混。即 LENGTH() 方法计算出来的长度,而不是 CHAR_LENGTH() 方法计算出来的长度。

数据类型 存储需求
CHAR(M) InnoDB 紧凑的行格式,优化了可变长度字符集的存储,见下面对 CHAR 类型的说明。否则应该是 M × w 字节,0 <= M <= 255,其中 w 是字符集中最大长度字符所需的字节数。
BINARY(M) M bytes, 0 <= M <= 255
VARCHAR(M), VARBINARY(M) 当 0 <= L <= 255 bytes : L + 1 bytes
当 L > 255 bytes : L + 2 bytes
TINYBLOB, TINYTEXT L + 1 bytes, L <
BLOB, TEXT L + 2 bytes, L <
MEDIUMBLOB, MEDIUMTEXT L + 3 bytes, L <
LONGBLOB, LONGTEXT L + 4 bytes, L <
ENUM('value1','value2',...) 1 或 2 bytes,取决于枚举值的数量(最大为 65,535 个值)
SET('value1','value2',...) 1、2、3、4 或 8 个 bytes,取决于 set 成员的数量(最大 64 个成员)

要计算用于存储特定 CHAR、VARCHAR 或 TEXT 列值的字节数,必须考虑用于该列的字符集以及该值是否包含多字节字符。特别是,在使用 UTF-8 Unicode 字符集时,必须记住并非所有字符使用相同的字节数。utf8mb3 和 utf8mb4 字符集可以分别要求每个字符最多 3 个字节和 4 个字节。

CHAR

在 MySql 内部,对于非可变长度字符集如 latin1,固定长度字符列,如 CHAR(10) 以固定长度格式存储。

对于如 utf8mb3 和 utf8mb4 等可变长度字符集,InnoDB 至少为 CHAR(N) 保留 N 个字节,并尝试通过修剪尾随空格将 CHAR(N) 存储在 N 个字节中。如果 CHAR(N) 列值的字节长度超过 N 个字节,则尾随空格将被修剪为列值字节长度的最小值。 CHAR(N) 列的最大长度是最大字符字节长度 × N。

在许多情况下,保留最小空间 N 可以在不导致索引页碎片的情况下就地完成列更新。相比之下,CHAR(N) 列在使用 REDUNDANT 行格式时占用最大字符字节长度 × N。

InnoDB 将长度大于等于 768 字节的定长字段编码为可变长字段,可以在页外存储。例如,如果字符集的最大字节长度大于 3,例如 utf8mb4,CHAR(255) 列就可以超过 768 字节。

可变长类型

VARCHAR、VARBINARY 以及 BLOB 和 TEXT 类型都是可变长类型。对于每一个,存储需求取决于以下因素:

  1. 列值的实际长度
  2. 列的最大可能长度
  3. 用于列的字符集,因为一些字符集包含多字节字符

例如,VARCHAR(255) 列可以容纳最大长度为 255 个字符的字符串。假设列使用 latin1 字符集(每个字符一个字节),实际需要的存储是字符串的长度 L,加上一个字节来记录字符串的长度。对于字符串 'abcd', 那么 L 是 4,存储要求是 5 个字节。如果这个列声明为使用 ucs2 双字节字符集,则存储要求为 10 字节:'abcd' 的长度是 8 个字节,该列需要 2 个字节来存储长度,因为最大长度大于 255 字节(最多 510 字节)。

VARCHAR 或 VARBINARY 列中可以存储的有效最大字节数受最大的行大小(65,535字节)的限制,该行大小在一行中的所有列之间共享。对于存储多字节字符的 VARCHAR 列,有效最大字符数更少。例如,utf8mb4 字符每个字符最多需要 4 个字节,因此可以将使用 utf8mb4 字符集的 VARCHAR 列声明为最大 16383 个字符。

ENUM

ENUM 对象的大小由不同枚举值的数量决定。1 个字节用于最多 255 个可能值的枚举。2 个字节用于 256 到65,535 个可能值之间的枚举。

SET

SET 对象的大小由不同 SET 成员的数量决定。如果设置的大小为 N,则对象占用 (N+7)/8 个字节,四舍五入到1、2、3、4 或 8 个字节。一个集合最多可以有 64 个成员。

空间类型

空间类型在 MySQL 内部以一种与 WKT 及 WKB 格式不完全相同的格式存储空间类型数据,格式是: 4 字节 SRID + WKB。

WKB 格式

WKB 使用 1 字节的无符号 Integer 标识字节顺序,4 字节的无符号 Integer 标识类型,及 8 字节的双精度 Double来记录坐标。

例如,对一个 POINT(1 -1) 的 WKB 数据就是由 21 个字节组成,每个字节由两个十六进制数字表示。

0101000000000000000000F03F000000000000F0BF
组成部分 长度
Byte order 1 bytes 01
WKB type 4 bytes 01000000
X coordinate 8 bytes 000000000000F03F
Y coordinate 8 bytes 000000000000F0BF

空间类型存储空间

mysql> SET @g = ST_GeomFromText('POINT(1 -1)');
mysql> SELECT LENGTH(@g);
+------------+
| LENGTH(@g) |
+------------+
|         25 |
+------------+
mysql> SELECT HEX(@g);
+----------------------------------------------------+
| HEX(@g)                                            |
+----------------------------------------------------+
| 000000000101000000000000000000F03F000000000000F0BF |
+----------------------------------------------------+

知道了 WKB 数据的组成方式,自然也就知道了 MySql 中对空间类型的存储大小了。

组成部分 长度 二进值 实际值
SRID 4byte 00000000 0
Byte order 1 bytes 01 little-endian
WKB type 4 bytes 01000000 Point
X coordinate 8 bytes 000000000000F03F 1
Y coordinate 8 bytes 000000000000F0BF -1

JSON 类型

一般来说,JSON 类型的存储需求与 LONGBLOB 或 LONGTEXT 类型的存储大致相同;也就是说,JSON 文档消耗的空间与存储在这些类型的列中的字符串表示大致相同。但是,存储在 JSON 文档中的单个值的二进制编码(包括查找所需的元数据和字典)会带来额外的开销。例如,存储在 JSON 文档中的字符串需要 4 到 10 个字节的额外存储,这取决于字符串的长度和存储它的对象或数组的大小。

另外,MySQL 对 JSON 列中存储的任何 JSON 文档的大小施加了限制,不能超过 max_allowed_packet 的值。

Data Type Storage Requirements

Supported Spatial Data Formats

有关MySql 数据类型所占存储空间的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  3. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  4. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  5. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

    我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

  6. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  7. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  8. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  9. ruby - Rack:如何将 URL 存储为变量? - 2

    我正在编写一个简单的静态Rack应用程序。查看下面的config.ru代码:useRack::Static,:urls=>["/elements","/img","/pages","/users","/css","/js"],:root=>"archive"map'/'dorunProc.new{|env|[200,{'Content-Type'=>'text/html','Cache-Control'=>'public,max-age=6400'},File.open('archive/splash.html',File::RDONLY)]}endmap'/pages/search.

  10. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

随机推荐