本节介绍 MySQL 数据类型在 NDBCLUSTER 表列中的表示方式,以及如何在 NDB API 应用程序中访问这些值。
数值数据类型。 MySQL TINYINT
、SMALLINT
、INT
和 BIGINT
数据类型映射到 NDB
类型,它们与 MySQL 对应类型的名称和存储要求相同。
MySQL FLOAT
和 DOUBLE
数据类型映射到 NDB
类型,它们与 MySQL 对应类型的名称和存储要求相同。
用于字符数据的类型。 MySQL CHAR
列所需的存储空间由最大字符数和列的字符集决定。对于大多数(但并非全部)字符集,每个字符占用一个字节的存储空间。当使用 utf8
时,每个字符需要三个字节;utfmb4
使用最多四个字节来存储每个字符。您可以通过检查 SHOW CHARACTER SET
输出的 Maxlen
列,找到给定字符集中每个字符需要的最大字节数。
一个 NDB
VARCHAR
列值映射到 MySQL VARCHAR
,但 NDB
VARCHAR
的前两个字节保留用于字符串的长度。像这里显示的实用程序函数可以使 VARCHAR
值准备好在 NDB API 应用程序中使用
void make_ndb_varchar(char *buffer, char *str)
{
int len = strlen(str);
int hlen = (len > 255) ? 2 : 1;
buffer[0] = len & 0xff;
if( len > 255 )
buffer[1] = (len / 256);
strcpy(buffer+hlen, str);
}
您可以像这里显示的示例一样使用该函数
char myVal[128+1]; // Size of myVal (+1 for length)
...
make_ndb_varchar(myVal, "NDB is way cool!!");
myOperation->setValue("myVal", myVal);
有关使用 NDB API 将 VARCHAR
和 VARBINARY
值写入和读取表的完整示例程序,请参见 第 2.5.12 节“NDB API 简单数组示例”。
MySQL 对 VARCHAR
或 VARBINARY
列的存储要求取决于列是在内存中存储还是在磁盘上存储
对于内存中的列,
NDB
存储引擎支持宽度可变的列,并进行 4 字节对齐。这意味着(例如)使用latin1
字符集存储在VARCHAR(50)
列中的字符串'abcde'
需要 12 个字节 - 在这种情况下,2 个字节乘以 5 个字符为 10,向上舍入到最接近的 4 的倍数,得到 12。对于磁盘数据列,
VARCHAR
和VARBINARY
作为宽度固定的列存储。这意味着这些类型中的每一个都需要与相同大小的CHAR
相同的存储空间。
在本 指南 中,我们始终将 MySQL 的任何 TEXT
或 BLOB
类型中的列称为 “blob 列”,其类型称为 “blob”。NDB 7.5 及更高版本也将 MySQL JSON
列视为 blob 列。
NDB Cluster BLOB
或 TEXT
列中的每一行都由两个独立的部分组成。其中一个部分大小固定(256 字节),实际上存储在原始表中。另一部分包含超过 256 字节的所有数据,存储在一个隐藏的 blobs 表中,该表的行始终为 2000 字节长。这意味着 TEXT
或 BLOB
列中大小为 size
字节的记录需要
256 个字节,如果
size
<= 256256 + 2000 * ((
字节,否则size
– 256) \ 2000) + 1)
时间数据类型。 时间类型在 NDB API 中的存储方式取决于使用的是没有小数秒的 MySQL “旧” 类型还是支持小数秒的 “新” 类型。对小数秒的支持是在 MySQL 5.6 以及基于它的 NDB Cluster 版本中引入的 - 即 NDB 7.3 和 NDB 7.4。这些版本以及更高版本的 MySQL Server 和 NDB Cluster 默认使用新的时间类型,可以读取和写入使用旧时间类型的数据,但不能创建使用旧类型的表。有关更多信息,请参见 时间值中的小数秒。
由于预计在未来版本中会删除对旧时间类型的支持,因此建议您将所有使用旧时间类型的表迁移到这些类型的新版本。您可以通过对使用旧时间的任何表执行复制 ALTER TABLE
操作来实现这一点,或者通过备份和还原所有这样的表来实现这一点。
您可以通过检查 NDB Cluster 发行版提供的 ndb_desc 实用程序的输出,查看给定表是使用旧时间类型还是新时间类型。假设在一个名为 test
的数据库中,使用以下语句在未使用 --create-old-temporals
选项启动的 mysqld 上创建了一个表
CREATE TABLE t1 (
c1 DATETIME,
c2 DATE,
c3 TIME,
c4 TIMESTAMP,
c5 YEAR) ENGINE=NDB;
ndb_desc 输出的相关部分(Attributes
块)如下所示
$> ndb_desc -dtest t1
...
-- Attributes --
c1 Datetime2(0) NULL AT=FIXED ST=MEMORY
c2 Date NULL AT=FIXED ST=MEMORY
c3 Time2(0) NULL AT=FIXED ST=MEMORY
c4 Timestamp2(0) NOT NULL AT=FIXED ST=MEMORY DEFAULT 0
c5 Year NULL AT=FIXED ST=MEMORY
新的 MySQL 时间类型的名称以 2
为后缀(例如,Datetime2
),以将其与这些类型的旧版本区分开来。假设我们使用 --create-old-temporals=ON
选项重新启动 mysqld,然后使用以下语句创建表 t2
,该表也在 test
数据库中
CREATE TABLE t2 (
c1 DATETIME,
c2 DATE,
c3 TIME,
c4 TIMESTAMP,
c5 YEAR) ENGINE=NDB;
对该表执行 ndb_desc 所示的输出包含这里显示的 Attributes
块
$> ndb_desc -dtest t2
...
-- Attributes --
c1 Datetime NULL AT=FIXED ST=MEMORY
c2 Date NULL AT=FIXED ST=MEMORY
c3 Time NULL AT=FIXED ST=MEMORY
c4 Timestamp NOT NULL AT=FIXED ST=MEMORY DEFAULT 0
c5 Year NULL AT=FIXED ST=MEMORY
受影响的 MySQL 类型是 TIME
、DATETIME
和 TIMESTAMP
。这些类型的“新”版本在 NDB API 中分别反映为 Time2
、Datetime2
和 Timestamp2
,每个都支持小数秒,精度最高可达 6 位。新的变体使用整数值的 Big-Endian 编码,然后处理这些编码以确定每种时间类型的分量。
对于这些类型中每个类型的小数秒部分,精度会影响所需的字节数,如下表所示
表 2.2 NDB API 新时间类型的精度
精度 | 所需字节 | 范围 |
---|---|---|
0 | 0 | — |
1 | 1 | 0-9 |
2 | 1 | 0-99 |
3 | 2 | 0-999 |
4 | 2 | 0-9999 |
5 | 3 | 0-99999 |
6 | 3 | 0-999999 |
每种新的时间类型的分数部分以 Big-Endian 格式存储,即最高位字节位于最低地址处,使用必要的字节数。
接下来几段将介绍这些类型的新旧版本的二进制布局。
Time
:此类型的“旧”版本存储为一个 24 位有符号 int
值,以 Little-Endian 格式存储(最低位字节位于最低位地址)。字节 0(位 0-7)对应小时,字节 2(位 8-15)对应分钟,字节 2(位 16-23)对应秒,公式如下
value = 10000 * hour
+ 100 * minute
+ second
位 23 用作符号位;如果设置了此位,则时间值被认为是负数。
Time2
:这是“新”的 TIME
类型,存储为一个 3 字节 Big-Endian 编码值加上 0 到 3 字节的分数部分。整数部分的编码方式如下表所示
除了这个之外的任何分数字节都按之前描述的方式处理。
Date
:MySQL DATE
类型的表示在 NDB 版本之间保持不变,并且使用一个以 Little-Endian 顺序存储的 3 字节无符号整数。编码方式如下所示
Datetime
:“旧”的 MySQL DATETIME
类型由一个 64 位无符号值表示,以主机字节序存储,使用以下公式进行编码
value = second
+ minute * 102
+ hour * 104
+ day * 106
+ month * 108
+ year * 1010
DateTime2
:“新”的 DATETIME
被编码为一个 5 字节 Big-Endian,带有一个可选的分数部分,范围为 0 到 3 字节,分数部分按之前描述的方式处理。最高 5 个字节的编码方式如下所示
YearMonth
位被编码为 Year = YearMonth / 13
和 Month = YearMonth % 13
。
Timestamp
:此类型的“旧”版本使用一个 32 位无符号值,表示自 Unix 纪元开始以来的秒数,以主机字节序存储。
Timestamp2
:这是“新”版本的 TIMESTAMP
,使用 4 个字节,以 Big-Endian 编码表示整数部分(无符号)。可选的 3 字节分数部分的编码方式如本节前面所述。
附加信息。 在 ndb/src/common/util/NdbSqlUtil.cpp
中可以找到更多关于数据类型以及在 NDB API 中表达数据类型的示例信息。此外,请参阅第 2.5.14 节,“Timestamp2 示例”,其中提供了一个使用 Timestamp2
数据类型的简单 NDB API 应用程序示例。