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_BINBIN_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

更多讨论:http://mysql.rjweb.org/doc.php/uuid