PostgreSQLデータベースを使用して、HerokuでRailsにアプリを作成しました。
さまざまな場所でデータを作成できるモバイルデバイスと同期できるように設計されたテーブルがいくつかあります。そのため、自動インクリメント主キーに加えてGUIDを格納する文字列であるuuidフィールドがあります。uuidは、サーバーとクライアント間で通信されるものです。
サーバー側に同期エンジンを実装した後、常にuuid <-> idをマッピングする必要があるときにパフォーマンスの問題につながることに気付きました(オブジェクトを書き込むとき、保存する前にuuidを照会してidを取得する必要があり、データを送り返す場合は反対)。
現在、UUIDを主キーとしてのみ使用するように切り替えて、書き込みと読み取りをより簡単かつ高速にすることを考えています。
主キーとしてUUIDを使用すると、クラスター化された主キーインデックスを使用するときに、インデックスのパフォーマンスが低下する場合があります(インデックスの断片化)。 PostgreSQLはこの問題に苦しんでいますか、またはUUIDを主キーとして使用しても大丈夫ですか?
今日、私はすでにUUID列を持っているので、通常のid列を削除するので、ストレージに関してはより良いでしょう。
(私はHeroku Postgresに取り組んでいます)
いくつかのシステムではUUIDを主キーとして使用しており、非常にうまく機能しています。
uuid-ossp
拡張機能を使用することをお勧めします。postgresでUUIDを生成することもできます。
heroku pg:psql
psql (9.1.4, server 9.1.6)
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.
dcvgo3fvfmbl44=> CREATE EXTENSION "uuid-ossp";
CREATE EXTENSION
dcvgo3fvfmbl44=> CREATE TABLE test (id uuid primary key default uuid_generate_v4(), name text);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
dcvgo3fvfmbl44=> \d test
Table "public.test"
Column | Type | Modifiers
--------+------+-------------------------------------
id | uuid | not null default uuid_generate_v4() name | text |
Indexes:
"test_pkey" PRIMARY KEY, btree (id)
dcvgo3fvfmbl44=> insert into test (name) values ('hgmnz');
INSERT 0 1
dcvgo3fvfmbl44=> select * from test;
id | name
--------------------------------------+-------
e535d271-91be-4291-832f-f7883a2d374f | hgmnz
(1 row)
パフォーマンスへの影響の編集
常にワークロードに依存します。
整数の主キーには、類似データがより近くにある場所の利点があります。これは、たとえば、WHERE id between 1 and 10000
などの範囲タイプのクエリに役立ちますが、ロックの競合はさらに悪化します。
主キーのルックアップを常に行うという点で読み取りワークロードが完全にランダムである場合、測定可能なパフォーマンスの低下はないはずです。大きなデータタイプに対してのみ支払う必要があります。
このテーブルにたくさん書きますか?このテーブルは非常に大きいですか?私はこれを測定していませんが、そのインデックスを維持することに意味がある可能性があります。ただし、多くのデータセットではUUIDは問題ありません。UUIDを識別子として使用すると、いくつかの素晴らしい特性があります。
最後に、問題となったUUID PKで十分な大きさのテーブルを実行したことがないため、これについて議論したりアドバイスしたりするのに最も適格な人ではないかもしれません。 YMMV。 (それを言って、私はアプローチで問題に遭遇する人々の話を聞きたいです!)
受け入れられた答えが示すように、この場合、範囲クエリは遅いかもしれませんが、id
だけではありません。
自動インクリメントは自然に日付でソートされるため、自動インクリメントが使用されると、データはディスク(Bツリーを参照)に時系列に格納され、読み取りが高速化されます(HDDのシークなし)。たとえば、すべてのユーザーをリストすると、自然な順序は作成された日付順になり、自動インクリメントと同じであるため、SSDではHDDで範囲クエリがより速く実行されますが、SSDは常にランダムであるため、違いは存在しないと思いますアクセス(ヘッドシークなし、機械部品の関与なし、純粋な電気のみ)