固定長64のhex
形式の文字列をデータベースに格納するシナリオに取り組んでいます。明らかに、選択肢はBYTEA
とCHAR(64)
です。
最初の考えは、それをBYTEA
として格納する有効な16進文字列を適用することでしたが、私が評価した影響は、選択したクエリでのENCODE
の使用でした。
両方のテーブルに数百万行あることを考慮して、いくつかのパフォーマンスベンチマークを実行しました。
# A file query_with_char.sql
SELECT "key" FROM table_varchar;;
# A file query_with_binary.sql
SELECT ENCODE("key", 'hex') FROM table_binary;
pgbench -c 30 -T 120 -n -f ./query_with_binary.sql -f ./query_with_char.sql -P 5 -S my_db
SQL script 1: ./query_with_binary.sql
- weight: 1 (targets 33.3% of total)
- 236 transactions (34.6% of total, tps = 1.876072)
- latency average = 8896.888 ms
- latency stddev = 2548.701 ms
SQL script 2: ./query_with_varchar.sql
- weight: 1 (targets 33.3% of total)
- 225 transactions (33.0% of total, tps = 1.788628)
- latency average = 7164.604 ms
- latency stddev = 2209.866 ms
クエリENCODE
のパフォーマンスが通常の文字列と比較して速い理由を理解できません。 PostgreSQLは、文字列列をフェッチするよりも、100万行のエンコードをどのように高速に実行できますか?
誰かが上記のテストで何が間違っているのか説明できますか?
encode()
は非常に安価な関数です。私はあなたのテストで測定可能な影響をまったく期待していません。
違いは、ほぼ確実に、char(64)
と比較してbytea
のはるかに小さいストレージサイズによるものです。考えてみましょう:
_SELECT pg_column_size('90b7525e84f64850c2efb407fae3f27190b7525e84f64850c2efb407fae3f271'::char(64)) AS size_char64
, pg_column_size(decode(text '90b7525e84f64850c2efb407fae3f27190b7525e84f64850c2efb407fae3f271', 'hex')) AS size_bytea;
size_char64 | size_bytea
-------------+------------
68 | 36
_
単純なSELECT
クエリのパフォーマンスの主な要因は、読み取られたデータページの数です。
明らかに、選択肢は
BYTEA
とCHAR(64)
です。
パフォーマンスを最適化することが目標である場合は、3番目のオプションを検討してください。
2 uuid
列
理解するには、最初に読んでください:
そして:
次に、このデモを検討します(11ページで実行されますが、すべての最新バージョンに当てはまります)。
RAMサイズ:
_SELECT pg_column_size(t64) AS c_text
, pg_column_size(t64::char(64)) AS c_char64
, pg_column_size(decode(t64, 'hex')) AS c_bytea
, pg_column_size( left(t64, 32)::uuid)
+ pg_column_size(right(t64, 32)::uuid) AS c_2x_uuid
FROM (SELECT text '90b7525e84f64850c2efb407fae3f27190b7525e84f64850c2efb407fae3f271') t(t64);
c_text | c_char64 | c_bytea | c_2x_uuid
--------+----------+---------+-----------
68 | 68 | 36 | 32
_
ディスクサイズ(圧縮形式):
_CREATE TEMP TABLE c64 AS
SELECT t64 AS c_text
, t64::char(64) AS c_char64
, decode(t64, 'hex') AS c_bytea
, left (t64, 32)::uuid AS c_uuid1
, right(t64, 32)::uuid AS c_uuid2
FROM (SELECT text '90b7525e84f64850c2efb407fae3f27190b7525e84f64850c2efb407fae3f271') t(t64);
SELECT pg_column_size(c_text) AS c_text
, pg_column_size(c_char64) AS c_char64
, pg_column_size(c_bytea) AS c_bytea
, pg_column_size(c_uuid1)
+ pg_column_size(c_uuid2) AS c_2x_uuid
FROM c64;
c_text | c_char64 | c_bytea | c_2x_uuid
--------+----------+---------+-----------
65 | 65 | 33 | 32
_
db <>フィドル ここ
いくつかのストレージメカニズムでは8バイトの倍数のパディングが必要なため、33ビットと32ビットのわずかな違いが実際には8バイトの違いを生む可能性があります。
2つのUUIDを使用してテストを繰り返します。私はそれが一番上に出ると確信しています。