列タイプをCHAR(36)からUUIDに変更する時間を費やすべきですか?


14

データベースにはすでに数百万行あります。スキーマを設計したとき、PostgreSQL UUIDデータ型について知りませんでした。

テーブルの1つには、1600万行(シャードあたり約350万から400万レコード)があり、1日あたり約50万レコードで増加します。必要に応じて、生産システムを数時間停止する余裕がまだあります。1週間か2週間でこの贅沢はありません。

私の質問は、そうする価値があるのでしょうか?JOINのパフォーマンス、ディスク領域の使用(gzipで圧縮された完全なダンプは1.25 GiB)、そのようなことについて疑問に思っています。

テーブルスキーマは次のとおりです。

# \d twitter_interactions
                Table "public.twitter_interactions"
         Column          |            Type             | Modifiers 
-------------------------+-----------------------------+-----------
 interaction_id          | character(36)               | not null
 status_text             | character varying(1024)     | not null
 screen_name             | character varying(40)       | not null
 twitter_user_id         | bigint                      | 
 replying_to_screen_name | character varying(40)       | 
 source                  | character varying(240)      | not null
 tweet_id                | bigint                      | not null
 created_at              | timestamp without time zone | not null
Indexes:
    "twitter_interactions_pkey" PRIMARY KEY, btree (interaction_id)
    "twitter_interactions_tweet_id_key" UNIQUE, btree (tweet_id)
    "index_twitter_interactions_on_created_at" btree (created_at)
    "index_twitter_interactions_on_screen_name" btree (screen_name)
Triggers:
    insert_twitter_interactions_trigger BEFORE INSERT ON twitter_interactions FOR EACH ROW EXECUTE PROCEDURE twitter_interactions_insert_trigger()
Number of child tables: 9 (Use \d+ to list them.)

回答:


13

UUIDタイプへの変更を検討します。 char(36)40バイト、uuid16 バイトかかるので、1行あたり24バイト節約できます。これは、1日12 MB、1年後に4 GBに相当します。プラスインデックス。使用しているハードウェアに応じて、それは大したことではありませんが、可能性はあります。そして、このような改善の機会があれば、それは合計されます。

また、スキーマinteraction_idが実際に正しい形式であることを保証する制約はありません。適切なタイプを使用すると、それも得られます。

ただし、これが気に入った場合は、使用bigintするよりもさらに節約でき、パフォーマンスがさらに向上します。アプリケーションが非常に大きくbigint、ID列のが機能しないことはほとんどありません。


分散システムがあります。複数のデータソースが相互作用のIDを生成するため、ノードIDにNビットを予約しない限り、プレーンなBIGINTを使用できません。
フランソワボーソレイユ

3
@FrançoisBeausoleil、ノードIDにNビットを予約することは、シーケンス内のN番目ごとの数を使用することと同じです(したがって、実装が簡単です)。また、複合キーの使用を検討することもできます。
Unreason

1
複数のシーケンスを(ノードIDを使用して)調整することは、実際には管理上の手間であり、人為的エラーを起こしやすいです。このシナリオではUUIDを使用しない理由はありません。特に、最近ではビット(メモリとストレージの両方)が安価であるためです。実際、このシナリオは、UUIDが数十年前に発明されたまさにその理由です:集中調整なしで分散システム間でデータを共有すること
バジルブルク

6

私は想像を超えてpostgresの人ではありませんが、SQL Serverから知っていることに基づいて、データページに収まる行が多いほど、パフォーマンスが向上します(ディスクからのデータの読み取りは通常最も高価な操作)。したがって、36からっぽい1 16バイトのバイト幅のフィールドGUIDは、まっすぐなコスト削減です。読み取ることができる読み取りが少ないほど、結果を早く返すことができます。もちろん、これはすべて、GUID / UUIDがテーブルのビジネスニーズを満たすことを前提としています。UUIDがそれを満たしている場合、bigintでしょうか?これにより、ストレージのコストが行ごとにさらに8バイト削減されます。

編集1

以下のために文字データのPostgresで、彼らのために追加のストレージ・コストがあります。127バイト未満の短い文字列には1バイトのオーバーヘッドがあり、長いものには4バイトがあるため、2番目の回答者は36バイトのフィールドに対して40バイトのコストを考え出しました。しかし、文字列圧縮のオプションもあるので、おそらく40を完全に消費することはありません。最終的なコストがどうなるかわかりませんが、基本は残ります。より多くのメモリを消費します。

短い文字列(最大126バイト)のストレージ要件は、1バイトに実際の文字列を加えたもので、文字の場合はスペースの埋め込みが含まれます。長い文字列には1ではなく4バイトのオーバーヘッドがあります。長い文字列はシステムによって自動的に圧縮されるため、ディスク上の物理的要件は少なくなります。


3

スペースの問題に加えて、正しいデータ型を使用するにはすべてのテーブルを変更する必要があります。そうしないと、結合のパフォーマンスが低下します。


それは当たり前のことでしたが、思い出させてくれてありがとう。
フランソワボーソレイユ

3
このような大きな変更を行うとき、すべてを書き留めること(覚えることがどんなに簡単であっても)は通常報われることがわかります。
-mrdenny

3

I / Oの節約につながるデータとインデックスのサイズの節約(他の人によると)に加えて、考慮する必要があるのは、新しい値をどのように生成しinteraction_id、どのような影響を与えるかですインデックスとクエリ条件(結合)。

インデックスの場合は小さくなりますが、多くのクエリでインデックススキャンを使用すると、UUIDに切り替えるとインデックススキャンが不可能になる可能性があります(UUIDの生成方法によって異なります)。 bigintより適切な選択になる可能性があります。

最後に、実際のパフォーマンスへの影響は使用パターンデータ分散にも依存するため、テストを実行し、変更をテストできる開発およびテスト環境を用意する必要があります。

これにより、パフォーマンスへの影響に関するより正確な答えが得られます。


有益な貢献に感謝し、サイトへようこそ:)
ジャックダグラス

私のアクセスパターンは、日付範囲、screen_nameを使用した参加、またはUUIDによるものです。一意のIDでの範囲スキャンは想定されていません。非常に有益な回答をありがとう。
フランソワボーソレイユ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.