ULID: Universally Unique Lexicographically Sortable Identifier

2025/12/02 5:45

ULID: Universally Unique Lexicographically Sortable Identifier

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

ULID(Universally Unique Lexicographically Sortable Identifier)は、URLセーフで大文字小文字を区別せず、PostgreSQL の UUID カラムに直接使用できるため、UUID に対する優れた代替案として提示されています。

ULID は 48 ビットのタイムスタンプとその後に 80 ビットの暗号学的ランダム性をエンコードし、合計で 128 ビット(≈ 26 文字の Base32)となります。時間プレフィックスにより、新しい ID が常に古いものより辞書式順序で大きくなるため、ランダム UUID v4 によるインデックス断片化が排除されます。

oklog/ulid
パッケージを用いた実際の Go の例では、ULID が
database/sql/driver.Valuer
encoding.TextMarshaler
を実装しているため、UUID プライマリキーを持つテーブルに直接挿入できることが示されています。同じコードで UUID v4 も比較用に挿入し、変換なしで互換性があることを確認しています。

ULID は 1.21 × 10²⁴ 個のユニーク ID を毎ミリ秒生成でき、ほぼすべてのアプリケーションに十分です。その短さは URL をクリーンに保ちます(例:

/users/01KANDQMV608PBSMF7TM9T1WR4ULID
)。

注意点として、高書き込みシステムでは多くの ID が同じミリ秒タイムスタンププレフィックスを共有するため、潜在的に「ホットスポット」遅延が発生する可能性があります。CUID や NanoID などの代替案もありますが、ULID のソート性・一意性・UUID 互換性の組み合わせが採用を促進しています。

新興の UUID v7 標準は、古い UUID が抱えるパフォーマンス問題に対処するために、同様の時間順序構造を採用しています。

本文

UUID形式はユニーク識別子として非常に広く使われている標準です。
しかし、その普及度と裏腹に、いくつかの固有制限から多くの一般的なユースケースでは最適とは言えません:

  • 文字数が多く、人間が読み取りやすいわけでもありません。
  • UUID v1/v2 は環境によっては実用性が低く、MACアドレスを取得できる安定したネットワークカードが必要です。
  • UUID v3/v5 では一意のシード値が必須になります。
  • UUID v4 は真にランダムであるため、B‑Tree 等のデータ構造上でインデックスの断片化を招き、書込み性能を低下させることがあります。

私が携わったプロジェクトでは ULID(Universally Unique Lexicographically Sortable Identifier)を採用し、大変満足しています。Go で Postgres を使うケースに焦点を当てつつ、同じ原理は他言語・他データベースでも応用可能です。

仕様全体はここで確認できます:
https://github.com/ulid/spec


ULID が従来の UUID バージョンの欠点を解消する理由

ULID は次の四つの特性に重点を置いています:

  1. 辞書順ソート可能 – ID をそのまま並べ替えられるため、データベースインデックスで最大のメリットとなります。
  2. 大文字小文字非区別 – 特殊文字を含まず URL でも安全に使用できます。
  3. UUID と互換性 – Postgres の
    UUID
    カラム型とそのまま使えるため、スキーマ変更は不要です。

構造

ULID は UUID 同様 128 ビットですが、機能別に構成されています:

|   48ビット(タイムスタンプ)   |          80ビット(暗号学的に安全な乱数)          |
|----------|             |----------------|

例:

01AN4Z07BY79KA1307SR9X4MV3


デモ:Go + Postgres +
pgx
ドライバ

以下のコードは、稼働中の PostgreSQL に接続し、主キーを

UUID
型にしたテーブルを作成します。その後、標準 UUID v4 と ULID の両方でレコードを挿入します。

package main

import (
	"context"
	"fmt"

	"github.com/google/uuid"
	"github.com/jackc/pgx/v5"
	"github.com/oklog/ulid/v2"
)

func main() {
	ctx := context.Background()

	conn, err := pgx.Connect(ctx, "postgres://...")
	if err != nil {
		panic(err)
	}
	defer conn.Close(ctx)

	_, err = conn.Exec(ctx, `
CREATE TABLE IF NOT EXISTS ulid_test (
  id UUID PRIMARY KEY,
  kind TEXT NOT NULL,
  value TEXT NOT NULL
);`)
	if err != nil {
		panic(err)
	}

	for i := 1; i <= 5; i++ {
		insertUUID(ctx, conn, fmt.Sprint(i))
	}
	for i := 1; i <= 5; i++ {
		insertULID(ctx, conn, fmt.Sprint(i))
	}
}

func insertUUID(ctx context.Context, conn *pgx.Conn, value string) {
	id := uuid.New()
	conn.Exec(ctx, "INSERT INTO ulid_test (id, value, kind) VALUES ($1, $2, 'uuid')", id, value)

	fmt.Printf("Inserted UUID: %s\n", id.String())
}

func insertULID(ctx context.Context, conn *pgx.Conn, value string) {
	id := ulid.Make()

	// ULID は文字列化せずそのまま使えます。
	conn.Exec(ctx, "INSERT INTO ulid_test (id, value, kind) VALUES ($1, $2, 'ulid')", id, value)

	fmt.Printf("Inserted ULID: %s\n", id.String())
}

oklog/ulid
パッケージは
database/sql/driver.Valuer
encoding.TextMarshaler
を実装しているため、Postgres の
UUID
カラムに自動で変換されます。これにより、スキーマを変更せずに ULID のソート利点を活用できます。


挿入時刻順のソート

タイムスタンプ付きプレフィックスのおかげで、新しい ULID は常に古いものより大きくなり、インデックス内では後に挿入されたレコードが末尾に物理的に配置されます。対照的に UUID v4 のランダム性はインデックス全体に分散します。

例:

SELECT * FROM ulid_test WHERE kind = 'ulid' ORDER BY id;

結果:

idkindvalue
019aaae4-be9c-d307-238f-be1692b3e8d7ulid1
019aaae4-be9d-011f-b82e-b870ca2abe9dulid2
019aaae4-be9f-e9d7-6efc-5b298ecc572bulid3
019aaae4-bea0-deae-6408-d89e7e3ce030ulid4
019aaae4-bea1-8ed2-c2f5-144bb1ffeddeulid5

レコードは挿入順と同じ順序で返されます。


URL にも最適

ULID は URL に組み込みやすく、短く洗練された表記です:

/users/01KANDQMV608PBSMF7TM9T1WR4

1 ミリ秒あたり約 1.21 × 10²⁴ 通りの一意 ID を生成できるため、多くのアプリケーションに十分な容量があります。


制限事項

極端に高頻度で書き込みを行うシステムでは、現在時刻周辺に集中する書き込みがホットスポットとなり、特定のインデックスブロックで遅延や性能低下が起こる可能性があります。


代替案と将来

CUID や NanoID 等も存在しますが、ULID の利点はユニーク識別子標準として大きな影響力を持っています。最新の提案では UUID v7 が登場し、時間順序構造を採用して旧バージョンのソート性と性能問題を解決することを目指しています。

YouTube チャンネルでさらにデモをご覧ください。

同じ日のほかのニュース

一覧に戻る →

2025/12/10 0:00

Show HN: Gemini Pro 3 hallucinates the HN front page 10 years from now

## Japanese Translation: ## 改訂版まとめ この記事では、最近のさまざまな技術的マイルストーンとリリースをレビューしています。 1. **SpaceX**:Starship HLS‑9 が Sea of Tranquility からテレメトリーを正常に送信しました。 2. **Linux Kernel**:バージョン 7.4 に完全な上流化された 100 % Rust カーネルが含まれています。 3. **開発者プラクティス**:生のコードを書くこととコンパイラプロンプトを使用することを対比した議論があります。 4. **人工知能**:LLaMA‑12 7B モデルは WebAssembly を介してコンタクトレンズ上で動作し、YC シード付きスタートアップ Nia は自律型コーディングエージェントを導入しています。 5. **教育ツール**:AlgoDrill は LeetCode パターンの強化に向けたインタラクティブなプラットフォームを提供します。 6. **エネルギー研究**:ITER の炉は 20 分間連続で正のエネルギー収支を達成しました。 7. **ハードウェア修理**:2024 年製 Framework Laptop を復元する方法を詳細に説明したレトロスペクティブガイドがあります。 8. **クラウドサービス**:Google は Gemini Cloud Services の提供を終了します。 9. **グラフィックスプログラミング**:WebGPU 2.0 により第 5 次元の可視化が可能になりました。 10. **Linux ディストリビューション**:Debian がバージョン 18 “Trixie” をリリースしました。 11. **プログラミング言語提案**:`sudo` ユーティリティを Zig で書き直す提案が提示されています。 この記事はこれらの出来事を文脈に置き、各々が過去の成功にどのように基づいているかを指摘し、その進歩が今後の開発実践、AI 統合、およびクラウドサービス戦略に影響を与えることを示唆しています。

2025/12/10 2:08

PeerTube is recognized as a digital public good by Digital Public Goods Alliance

## Japanese Translation: ### Summary PeerTubeはプラットフォームに依存しない多言語対応のビデオホスティングおよびライブストリーミングソリューションで、正式にデジタル公共財(DPG ID0092472)として承認されています。2025年10月7日にRicardo Torresによるレビューが行われ、Platform Independence評価を含むすべてのDPG標準要件を満たしていることが確認されました。これにより、ベンダーロックインなしで任意のインフラ上で実行できることが保証されています。ソースコードはGitHub(`github.com/Chocobozzz/PeerTube`)とFramagit(`framagit.org/framasoft/peertube`)で公開されており、透明性とコミュニティの貢献を確保しています。PeerTubeは44以上の言語(エスペラント、アラビア語、中国語簡体字・繁体字、日本語、韓国語、スペイン語、フランス語、ドイツ語、イタリア語、ポルトガル語、ロシア語など)をサポートし、フランスの教育省からイタリアの国家研究評議会、複数のドイツ大学、Blender、Debianプロジェクト、および活動家グループまで、多様な組織で既に利用されています。承認は2026年10月7日まで有効であり、毎年自己申告による使用状況更新が求められます。この推奨は、機関やオープンソースコミュニティが分散型ビデオプラットフォームを採用することを促進し、メディアホスティングの風景をよりオープンで多言語化、ベンダー非依存な解決策へとシフトさせる可能性があります。

2025/12/10 5:33

Django: what’s new in 6.0

## Japanese Translation: --- ## Django 6.0 – 主なリリースハイライト *リリース日 2025‑12‑03* | エリア | 変更点 | 意義 | |------|--------------|----------------| | **テンプレート** | 新しい `{% partialdef %}` / `{% endpartialdef %}` タグで、テンプレートを再利用可能なフラグメントに分割し、インラインまたは別途レンダリングでき、htmx とも相性が良い。 | テンプレートの DRY 化、ボイラープレート削減、コンポーネント再利用の容易化。 | | **バックグラウンドタスク** | 組み込み「Tasks」フレームワーク: `@task` デコレーター + `Task.enqueue()` API。組み込みバックエンド(`ImmediateBackend`、`DummyBackend`)があり、実稼働ではサードパーティパッケージ(例: `django-tasks` の `DatabaseBackend`)が必要。 | 単純なジョブに対して外部タスクライブラリの必要性を排除しつつ、実稼働時の柔軟性は維持。 | | **セキュリティ** | `ContentSecurityPolicyMiddleware` を追加。 `SECURE_CSP` と `SECURE_CSP_REPORT_ONLY` で設定可能。ノンスは自動生成され、テンプレート内では `{% csp_nonce %}`(`nonce="{{ csp_nonce }}"`)で使用できる。 | 自動ノンス処理付きの CSP サポートを組み込み、XSS リスクをデフォルトで低減。 | | **メール** | Django のメール API が Python の `email.message.EmailMessage` を利用するように変更。 `EmailMessage.send()` は内部でこの API に変換し、インライン添付は `MIMEPart` オブジェクトで追加可能。 | 標準ライブラリ互換のモダンなメール処理と簡易的な添付サポート。 | | **Mail API の非推奨** | `django.core.mail` API ではキーワード専用引数が必須となり、位置オプションパラメータは警告を出し将来的にエラーになる。 | より明確な API 使用を促進し、コードの未来保証を実現。 | | **シェル** | 自動インポートが拡張され、 `settings`、`connection`、`models`、`reset_queries`、`functions`、`timezone` が追加。 | もっと高速で便利な対話型開発環境。 | | **ORM** | • 動的フィールド(`db_default`、`GeneratedField`)は `save()` 後に SQL RETURNING を通じてリフレッシュされる;未対応バックエンドでは次回アクセス時まで遅延。<br>• `StringAgg` 集約がすべてのサポートデータベースで動作;文字列リテラル区切りは `Value()` で包む必要。<br>• デフォルト主キー型が `BigAutoField` に変更され、新規プロジェクトでは `DEFAULT_AUTO_FIELD` を設定しなくなる。 | モデル定義の簡素化、パフォーマンス向上、大規模アプリでの PK 終了防止。 | | **テンプレート変数 & タグ** | `forloop.length` が追加され、ループ長にアクセス可能;更新された `querystring` タグは `?` で接頭辞し、複数位置引数を受け取り、重複時には優先順位でマージ。 | より表現力豊かなテンプレートロジックとクリーンなクエリ文字列処理。 | | **コミュニティ** | Django 6.0 に 174 人の貢献者が参加。リリースノートではアップグレード準備を強調し、開発者に新機能を試すよう呼びかける;今後のリリースでタスクバックエンドや CSP 機能が拡張される可能性。 | 健全なコミュニティサポートとさらなる改善へのロードマップを示唆。 | **まとめ:** Django 6.0 は、再利用可能なテンプレートフラグメント、オプションの組み込みタスクシステム、ノンス付き CSP ミドルウェア、モダン化されたメール API など、実務で即使える改善を提供します。さらに ORM の強化、シェルの利便性向上、旧パターンの非推奨により、ボイラープレート削減・セキュリティ向上・大規模プロジェクトの将来準備が実現されます。 ---