sqlite-ulid 作者 asg017

星标

README 源代码

sqlite-ulid

一个 SQLite 扩展,用于生成和处理 ULID。构建于 sqlite-loadable-rsulid-rs 之上。

如果您的公司或组织觉得这个库很有用,请考虑支持我的工作

用法

.load ./ulid0

select ulid(); -- '01gqr4j69cc7w1xdbarkcbpq17'
select ulid_bytes(); -- X'0185310899dd7662b8f1e5adf9a5e7c0'
select ulid_with_prefix('invoice'); -- 'invoice_01gqr4jmhxhc92x1kqkpxb8j16'
select ulid_with_datetime('2023-01-26 22:53:20.556); -- '01gqr4j69cc7w1xdbarkcbpq17'
select ulid_datetime('01gqr4j69cc7w1xdbarkcbpq17') -- '2023-01-26 22:53:20.556'

用作表的 PRIMARY KEY(主键)。

create table log_events(
  id ulid primary key,
  data any
);


insert into log_events(id, data) values (ulid(), 1);
insert into log_events(id, data) values (ulid(), 2);
insert into log_events(id, data) values (ulid(), 3);

select * from log_events;
/*
┌────────────────────────────┬──────┐
│             id             │ data │
├────────────────────────────┼──────┤
│ 01gqr4vr487bytsf10ktfmheg4 │ 1    │
│ 01gqr4vr4dfcfk80m2yp6j866z │ 2    │
│ 01gqr4vrjxg0yex9jr0f100v1c │ 3    │
└────────────────────────────┴──────┘
*/

考虑使用 ulid_bytes() 以提高速度和获得更小的 ID。它们的生成速度比 ulid() 快约 1.6 倍,并且占用 16 字节而不是 26 字节。您可以使用 ulid() 创建 BLOB ULID 的文本表示。

create table log_events(
  id ulid primary key,
  data any
);


insert into log_events(id, data) values (ulid_bytes(), 1);
insert into log_events(id, data) values (ulid_bytes(), 2);
insert into log_events(id, data) values (ulid_bytes(), 3);

select hex(id), ulid(id), data from log_events;
/*
┌──────────────────────────────────┬────────────────────────────┬──────┐
│             hex(id)              │          ulid(id)          │ data │
├──────────────────────────────────┼────────────────────────────┼──────┤
│ 0185F0539EBF286DA9F56BA4D9981783 │ 01gqr577nz51ptkxbbmkcsg5w3 │ 1    │
│ 0185F0539EC54F85745C1ECB64DF3A97 │ 01gqr577p59y2q8q0ysdjdyemq │ 2    │
│ 0185F0539ED48113F6F67BF3F6A4BFF7 │ 01gqr577pmg49zdxkvyfva9fzq │ 3    │
└──────────────────────────────────┴────────────────────────────┴──────┘
*/

使用 ulid_datetime() 提取 ULID 的时间戳部分。

select ulid_datetime(ulid()); -- '2023-01-26 23:07:36.508'
select unixepoch(ulid_datetime(ulid())); -- 1674774499
select strftime('%Y-%m-%d', ulid_datetime(ulid())); -- '2023-01-26''

考虑使用 ulid_with_prefix() 生成带有给定前缀的文本 ULID,以区分不同类型的 ID。

select ulid_with_prefix('customer'); -- 'customer_01gqr5j1ebk31wv30wgp8ebehj'
select ulid_with_prefix('product'); -- 'product_01gqr5prjgsa77dhrxf2dt1dgv'
select ulid_with_prefix('order'); -- 'order_01gqr5q35n68jk0sycy1ntr083'

快速基准测试

并非最终结果,在 Macbook 上匆忙运行,不代表实际使用场景。uuid() SQL 函数来自 官方的 uuid.c 扩展

测试用例 时间
generate_series() 生成 100 万行 28.5 毫秒 ± 0.8 毫秒 (1 倍)
调用 ulid_bytes() 100 万次 88.4 毫秒 ± 2.8 毫秒,慢 3.10 ± 0.13
调用 uuid() 100 万次 141.6 毫秒 ± 1.5 毫秒,或慢 4.97 ± 0.15
调用 ulid() 100 万次 344.3 毫秒 ± 11.9 毫秒,或慢 12.07 ± 0.53

因此 ulid_bytes() 速度相当快,但返回的是不可读的 BLOB,而不是格式良好的文本 ID。ulid() 函数可以返回文本 ID,但速度比 uuid() 慢两倍以上。

然而,在约 350 毫秒内生成 100 万个 ulid() ID 对于大多数 SQLite 用例来说很可能“足够好”了。

使用方法(针对不同环境)...

语言/环境 安装
Python pip install sqlite-ulid PyPI
Datasette datasette install datasette-sqlite-ulid Datasette
Node.js npm install sqlite-ulid npm
Deno deno.land/x/sqlite_ulid deno.land/x release
Ruby gem install sqlite-ulid Gem
Rust cargo add sqlite-ulid Crates.io
Github 发布页 GitHub tag (latest SemVer pre-release)

发布页包含适用于 Linux x86_64、MacOS 和 Windows 的预构建二进制文件。

Python

对于 Python 开发者,可以使用以下命令安装 sqlite-ulid

pip install sqlite-ulid
import sqlite3
import sqlite_ulid
db = sqlite3.connect(':memory:')
db.enable_load_extension(True)
sqlite_ulid.load(db)
db.execute('select ulid()').fetchone()
# ('01gr7gwc5aq22ycea6j8kxq4s9',)

更多详细信息请参阅 python/sqlite_ulid

Node.js

对于 Node.js 开发者,可以使用以下命令安装 sqlite-ulid npm 包

npm install sqlite-ulid
import Database from "better-sqlite3";
import * as sqlite_ulid from "sqlite-ulid";

const db = new Database(":memory:");
db.loadExtension(sqlite_ulid.getLoadablePath());

更多详细信息请参阅 npm/sqlite-ulid/README.md

Deno

对于 Deno 开发者,请使用 deno.land/x/sqlite_ulid 模块:

()!; console.log(version);">
import { Database } from "https://deno.land/x/sqlite3@0.8.0/mod.ts";
import * as sqlite_ulid from "https://deno.land/x/sqlite_ulid@v${VERSION}/mod.ts";

const db = new Database(":memory:");

db.enableLoadExtension = true;
sqlite_ulid.load(db);

const [version] = db.prepare("select ulid_version()").value<[string]>()!;

console.log(version);

Datasette

对于 Datasette,可以使用以下命令安装 datasette-sqlite-ulid 插件

datasette install datasette-sqlite-ulid

更多详细信息请参阅 python/datasette_sqlite_ulid

作为可加载扩展

如果您想将 sqlite-ulid 用作运行时可加载扩展,请从发布页下载 ulid0.dylib(用于 MacOS)、ulid0.so(用于 Linux)或 ulid0.dll(用于 Windows)文件,并将其加载到您的 SQLite 环境中。

注意:文件名中的 0ulid0.dylib / ulid0.so / ulid0.dll)表示 sqlite-ulid 的主版本号。目前 sqlite-ulid 处于 v1 之前,因此未来版本可能会有重大更改。

例如,如果您使用SQLite 命令行界面,您可以按如下方式加载库:

.load ./ulid0
select ulid_version();
-- v0.1.0

在 Python 中,您应该首选 sqlite-ulid Python 包。但是,您也可以使用内置的 sqlite3 模块手动加载预编译扩展:

import sqlite3
con = sqlite3.connect(":memory:")
con.enable_load_extension(True)
con.load_extension("./ulid0")
print(con.execute("select ulid_version()").fetchone())
# ('v0.1.0',)

或者在 Node.js 中使用 better-sqlite3

const Database = require("better-sqlite3");
const db = new Database(":memory:");
db.loadExtension("./ulid0");
console.log(db.prepare("select ulid_version()").get());
// { 'ulid_version()': 'v0.1.0' }

使用 Datasette 时,您应该首选 datasette-sqlite-ulid Datasette 插件。但是,您也可以像这样将预编译扩展手动加载到 Datasette 实例中:

datasette data.db --load-extension ./ulid0

支持我的工作

我(Alex 👋🏼)在这个项目和许多其他开源项目上花费了大量时间和精力。如果您的公司或组织使用这个库(或者您乐于助人),请考虑支持我的工作,或者将这个项目分享给朋友!

另请参阅

  • sqlite-xsv,一个用于处理 CSV 的 SQLite 扩展
  • sqlite-loadable,一个用 Rust 编写 SQLite 扩展的框架
  • sqlite-http,一个用于发出 HTTP 请求的 SQLite 扩展