instagram key format を使用しているプロジェクトで作業しています。
TL; DR 64ビット整数ID。
これらはルックアップに使用されます。また、作成時間で自然にソートされるため、ソートやバッチ処理にも適しています。
値は2 ^ 63と2 ^ 64の間なので、([])大きすぎてBIGINT
の内側に収まりません。
したがって、ストレージのオプションはnumeric(20)
またはvarchar
のようです。 varchar
は、並べ替えを機能させるためにゼロを埋め込む必要があるため、理想的ではありませんが、ルックアップに数値を使用するとパフォーマンスに影響がありますか?
キャプテンになるのは嫌いですが、 Instagramは、あなたがリンクした関数を提供しており、キーをbigint
として保存しています です。
_CREATE SCHEMA insta5;
CREATE SEQUENCE insta5.table_id_seq;
CREATE OR REPLACE FUNCTION insta5.next_id(OUT result bigint) AS $$
DECLARE
our_Epoch bigint := 1314220021721;
seq_id bigint;
now_millis bigint;
shard_id int := 5;
BEGIN
-- The %1024, is just a way of saying they only want 10bit wraparound.
SELECT nextval('insta5.table_id_seq') % 1024 INTO seq_id;
SELECT FLOOR(EXTRACT(Epoch FROM clock_timestamp()) * 1000) INTO now_millis;
result := (now_millis - our_Epoch) << 23;
result := result | (shard_id << 10);
result := result | (seq_id);
END;
$$ LANGUAGE plpgsql;
_
彼らは実際にPostgreSQLを使用しています。その関数から、bigint
が返されていることがわかります。 そのため、確かにその関数の結果をbigint
に保存できます。特別な注意として、これはおそらくそれらの関数ではありません再使用。その関数はおそらくこのようなシグネチャを持っています。
_insta5.next_id(smallint shard, OUT result bigint);
_
_5
_のシャードをハードコーディングすることはそれほど有用ではなく、この機能を使用していることを示しているようです。そのブログIDでは、IDの妥協を自慢しています
彼らのコードのクイックテスト、
_test=# SELECT insta5.next_id();
next_id
---------------------
1671372309237077023
(1 row)
_
さあ遊びましょう。さらにセクシーにするには、IDから内部コンポーネントを取得するヘルパー関数を作成できます。 Instagramが使用しているシャードまたは内部のタイムスタンプを知りたい場合。
_-- 13 bits for shard
CREATE FUNCTION insta5.get_shard(id bigint)
RETURNS smallint
AS $$
SELECT ((id<<41)>>51)::smallint;
$$ LANGUAGE sql;
-- 10 bits for sequence id
CREATE FUNCTION insta5.get_sequence(id bigint)
RETURNS smallint
AS $$
SELECT ((id<<54)>>54)::smallint;
$$ LANGUAGE sql;
-- 41 bits for timestamp
CREATE OR REPLACE FUNCTION insta5.get_ts(id bigint)
RETURNS timestamp without time zone
AS $$
SELECT to_timestamp(((id >> 23) + 1314220021721 ) / 1000 )::timestamp without time zone;
$$ LANGUAGE sql;
_
遊んで、テストIDを取得しましょう。
_SELECT insta5.next_id();
next_id
---------------------
1671390786412876801
(1 row)
SELECT
insta5id,
insta5.get_ts(insta5id),
insta5.get_shard(insta5id),
insta5.get_sequence(insta5id)
FROM (VALUES
(1671390786412876801::bigint),
(insta5.next_id())
) AS t(insta5id);
_
次を返します、
_ insta5id | get_ts | get_shard | get_sequence
---------------------+---------------------+-----------+--------------
1671390786412876801 | 2017-12-16 17:02:09 | 5 | 1
1671392537048257538 | 2017-12-16 17:05:38 | 5 | 2
(2 rows)
_
これを完全にクリーンアップしたい場合は、型に明示的なDOMAIN
を作成することもできます。これは私がこれを個人的に保存する方法です。さらにいくつか変更を加えました。
COMMENTS
を追加しました-常に良い習慣です。IMMUTABLE
insta5.next_id
_を追加しました。明示的なシャードが必要です。私たちが持っていたものを落としましょう、
_DROP SCHEMA insta5 CASCADE;
_
そして、最初から
_CREATE SCHEMA insta5;
COMMENT ON SCHEMA insta5 IS 'Instagram';
CREATE DOMAIN insta5.id AS bigint;
COMMENT ON DOMAIN insta5.id IS $$Instagram's internal ID type, based on example from "Sharding & IDs at Instagram"$$;
CREATE SEQUENCE insta5.table_id_seq;
CREATE OR REPLACE FUNCTION insta5.next_id(shard_id smallint)
RETURNS insta5.id
AS $$
DECLARE
our_Epoch bigint := 1314220021721;
seq_id bigint;
result insta5.id;
now_millis bigint;
BEGIN
SELECT nextval('insta5.table_id_seq') % 1024 INTO seq_id;
SELECT FLOOR(EXTRACT(Epoch FROM clock_timestamp()) * 1000) INTO now_millis;
result := (now_millis - our_Epoch) << 23;
result := result | (shard_id << 10);
result := result | (seq_id);
RETURN result;
END;
$$ LANGUAGE plpgsql;
COMMENT ON FUNCTION insta5.next_id(smallint)
IS 'Modifications made to require shard id';
CREATE OR REPLACE FUNCTION insta5.get_shard(id insta5.id)
RETURNS smallint
AS $$
SELECT ((id<<41)>>51)::smallint;
$$ LANGUAGE sql
IMMUTABLE;
COMMENT ON FUNCTION insta5.get_shard(insta5.id)
IS '13 bits from insta5.id representing shard';
CREATE OR REPLACE FUNCTION insta5.get_sequence(id insta5.id)
RETURNS smallint
AS $$
SELECT ((id<<54)>>54)::smallint;
$$ LANGUAGE sql
IMMUTABLE;
COMMENT ON FUNCTION insta5.get_sequence(insta5.id)
IS '10 bits from insta5.id representing sequence';
CREATE OR REPLACE FUNCTION insta5.get_ts(id insta5.id)
RETURNS timestamp without time zone
AS $$
SELECT to_timestamp(((id >> 23) + 1314220021721 ) / 1000 )::timestamp without time zone;
$$ LANGUAGE sql
IMMUTABLE;
COMMENT ON FUNCTION insta5.get_ts(insta5.id)
IS '41 bits from insta5.id representing timestamp';
_
すべては以前と同じように機能しますが、今はできます
_CREATE SCHEMA mySchema;
CREATE TABLE mySchema.mydata ( insta5id insta5.id ) ;
_
これはおそらくC実装の恥ずかしがり屋を得ることができる最良の解決策であり、おそらく_insta5id
_を生成したくないでしょう。それが彼らの仕事です。 ;)
もう1つ重要なことはさておき、あなたはおそらくこれをしたくありません。例に従ってはいけません。これが uuid
type の目的であり、自分でローリングするのではなく、使用する必要があります。具体的には、これはuuid_generate_v1()
in _uuid-ossp
_ 、MAC(シャード)、およびタイムスタンプを格納します
この関数は、バージョン1のUUIDを生成します。これには、コンピューターのMACアドレスとタイムスタンプが含まれます。この種類のUUIDは、識別子と時刻を作成したコンピューターのIDを明らかにすることに注意してください。そのため、セキュリティが重要な特定のアプリケーションには適さなくなる可能性があります。
numeric(20)
(14バイト)は、あらゆる点でbigint
(8バイト)より大きく、遅いです。そしてvarchar
またはtext
(同じこと)、20桁で24バイトを占有します。ただし、numeric
よりも低速です。さらに、明示的に定義されていない限り、文字タイプはCOLLATION
ルールで制限されます。
自分を試す:
SELECT pg_column_size((2^64 -1)::numeric) -- 14 bytes
, pg_column_size((2^64 -1)::numeric::text) -- 24 bytes
numeric
はまた、非数値がそのまま保存されることを許可しません(ニーズに適合)。
あなたの与えられたオプションに直面しました(2 ^ 63と2 ^ 64の間の値なので、大きすぎてbigint
に収まりません)numeric
を選択し、決して振り返りません。
関連:
Or Postgresプロジェクトのコアハッカーの1人であるPeter Eisentrautによる extension pguint
をインストールできます。
最初にreadmeを必ずお読みください。拡張機能は、いくつかの追加(ほとんどが符号なし)整数型を提供します。あなたはちょうどextraxt uint8
(符号なし64ビット整数)と残りを破棄して、型システムの混雑を回避します。
値は2 ^ 63から2 ^ 64の間なので、BIGINTに収まらないには(ただ)大きすぎます。
bigint
is -9223372036854775808 to +9223372036854775807 の範囲は、-2 ^ 63〜2 ^ 63-1または2 ^ 64の異なる整数です。識別子の範囲は2 ^ 63の異なる整数であるため、オフセットを気にしない限り、bigint
にうまく収まります。
select round(power(2::numeric,63::numeric)) "2^63" ,round(power(2::numeric,64::numeric)) "2^64" ,(9223372036854775808::numeric-9223372036854775809::numeric)::bigint "offset low val" ,(18446744073709551616::numeric-9223372036854775809::numeric)::bigint "offset high val";
2 ^ 63 | 2 ^ 64 |低値のオフセット|高値オフセット ------------------:| -------------------:| -------------:| ------------------: 9223372036854775808 | 18446744073709551616 | -1 | 9223372036854775807
dbfiddle ここ
私の例では-9223372036854775809(-2 ^ 63 + 1)のオフセットを使用していますが、bigint
をオーバーフローしないオフセットを自由に選択できます。
したがって、キーを提示するとき、およびオフセットを適用するときにnumeric
を使用する必要がありますが、実際にキーやソートなどの操作を格納するためではありません。