Efficient/Scalable 在 MySQL 上以二进制形式存储和检索 UUID 的方法
Efficient/Scalable way to store and retrieve UUID as binary on MySQL
我正在使用 UUID 作为 MySQL 上表的 PK (BINARY(16)
)。哪个选项更适合转换二进制 to/from UUID 字符串?
第一个选项是使用 MySQL 内置函数 UUID_TO_BIN
和 BIN_TO_UUID
。这是最容易处理的 UUID/binary 转换。但我想它可能会在某些时候导致性能问题。
第二个选项是运行应用层转换(Node.js)。这样,性能就不会成为大问题,因为 Web 服务器是可水平扩展的。但是,代码可能会有点混乱。
根据我的研究,Postgres 可以很好地处理 UUID。 MySQL 的性能是否与 Postgres 一样好并且无需担心性能?
我的每种方法的代码如下所示。
MySQL
INSERT INTO mytable SET id = UUID_TO_BIN("709fe2ce-be43-11ea-a4e2-784f439a6382", 1);
SELECT BIN_TO_UUID(id, 1) as id FROM mytable WHERE id = UUID_TO_BIN("709fe2ce-be43-11ea-a4e2-784f439a6382", 1);
申请(Node.js 带 knex)
async function add(data: DataType): Promise<void> {
await knex("mytable").insert({
...data,
id: toBinaryUUID(data.uuid),
});
}
async function find(uuid: string): Promise<DataType | undefined> {
const query = knex
.select("id")
.from("mytable")
.where("id", toBinaryUUID(uuid));
const record = await query.first();
if (record) {
record.id = fromBinaryUUID(record.id);
}
return record;
}
(我使用odo-network/binary-uuid作为转换函数。)
function fromBinaryUUID(buf: Buffer): string {
return [
buf.toString("hex", 4, 8),
buf.toString("hex", 2, 4),
buf.toString("hex", 0, 2),
buf.toString("hex", 8, 10),
buf.toString("hex", 10, 16),
].join("-");
}
function toBinaryUUID(uuid: string): Buffer {
const buf = Buffer.from(uuid.replace(/-/g, ""), "hex");
return Buffer.concat([
buf.slice(6, 8),
buf.slice(4, 6),
buf.slice(0, 4),
buf.slice(8, 16),
]);
}
在MySQL8中,应该会用到那些函数。
- 16 个字节优于 36 个字符(space,等等)
- 函数重新排列位,以便大约同时创建的 uuid 在 table 中彼此“接近”。这提供了参考的时间局部性,从而加快了重要的 class 查询。
- 手动转换例程可以(但可能不会)重新排列位。
- 只有第 1 类 uuid 从重新排列中受益,但这是 MySQL 使用的类型。
- 如果您的 uuid 来自其他地方,重新排列不会造成伤害,但可能无济于事。
- 如果您使用的不是 MySQL 8.0,这些例程不是内置的,但可以在下面的 link 中找到。
- 对于 MySQL 8.0,包括 swap_flag(第二个参数)作为
1
。
我正在使用 UUID 作为 MySQL 上表的 PK (BINARY(16)
)。哪个选项更适合转换二进制 to/from UUID 字符串?
第一个选项是使用 MySQL 内置函数 UUID_TO_BIN
和 BIN_TO_UUID
。这是最容易处理的 UUID/binary 转换。但我想它可能会在某些时候导致性能问题。
第二个选项是运行应用层转换(Node.js)。这样,性能就不会成为大问题,因为 Web 服务器是可水平扩展的。但是,代码可能会有点混乱。
根据我的研究,Postgres 可以很好地处理 UUID。 MySQL 的性能是否与 Postgres 一样好并且无需担心性能?
我的每种方法的代码如下所示。
MySQL
INSERT INTO mytable SET id = UUID_TO_BIN("709fe2ce-be43-11ea-a4e2-784f439a6382", 1);
SELECT BIN_TO_UUID(id, 1) as id FROM mytable WHERE id = UUID_TO_BIN("709fe2ce-be43-11ea-a4e2-784f439a6382", 1);
申请(Node.js 带 knex)
async function add(data: DataType): Promise<void> {
await knex("mytable").insert({
...data,
id: toBinaryUUID(data.uuid),
});
}
async function find(uuid: string): Promise<DataType | undefined> {
const query = knex
.select("id")
.from("mytable")
.where("id", toBinaryUUID(uuid));
const record = await query.first();
if (record) {
record.id = fromBinaryUUID(record.id);
}
return record;
}
(我使用odo-network/binary-uuid作为转换函数。)
function fromBinaryUUID(buf: Buffer): string {
return [
buf.toString("hex", 4, 8),
buf.toString("hex", 2, 4),
buf.toString("hex", 0, 2),
buf.toString("hex", 8, 10),
buf.toString("hex", 10, 16),
].join("-");
}
function toBinaryUUID(uuid: string): Buffer {
const buf = Buffer.from(uuid.replace(/-/g, ""), "hex");
return Buffer.concat([
buf.slice(6, 8),
buf.slice(4, 6),
buf.slice(0, 4),
buf.slice(8, 16),
]);
}
在MySQL8中,应该会用到那些函数。
- 16 个字节优于 36 个字符(space,等等)
- 函数重新排列位,以便大约同时创建的 uuid 在 table 中彼此“接近”。这提供了参考的时间局部性,从而加快了重要的 class 查询。
- 手动转换例程可以(但可能不会)重新排列位。
- 只有第 1 类 uuid 从重新排列中受益,但这是 MySQL 使用的类型。
- 如果您的 uuid 来自其他地方,重新排列不会造成伤害,但可能无济于事。
- 如果您使用的不是 MySQL 8.0,这些例程不是内置的,但可以在下面的 link 中找到。
- 对于 MySQL 8.0,包括 swap_flag(第二个参数)作为
1
。