web-dev-qa-db-ja.com

BYTEAのENCODEがパフォーマンスに影響を与えないように見えるのはなぜですか?

固定長64のhex形式の文字列をデータベースに格納するシナリオに取り組んでいます。明らかに、選択肢はBYTEACHAR(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万行のエンコードをどのように高速に実行できますか?

誰かが上記のテストで何が間違っているのか説明できますか?

1
Nazar Hussain

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クエリのパフォーマンスの主な要因は、読み取られたデータページの数です。

「最良の」データ型?

明らかに、選択肢はBYTEACHAR(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を使用してテストを繰り返します。私はそれが一番上に出ると確信しています。

2