だから、あなたはキーボードの上に手を置いて、「私の人生をさらに好奇心をそそるのに、どんなに楽しいことができるか」と考えます。もちろん、テーブルを作成してください!
vao=# create table nocol();
CREATE TABLE
vao=# select * from nocol;
--
(0 rows)
データのないテーブルの面白さは何ですか?..絶対にありません!しかし、私はそれを簡単に修正できます:
vao=# insert into nocol default values;
INSERT 0 1
列と1行のないテーブルがあるのは奇妙で非常に愚かに見えます。言うまでもなく、そこに挿入された「デフォルト値」は明確ではありません…まあ-ドキュメントから数行を読むと、「すべての列がデフォルト値で埋められます 。」しかし、私には列がありません!ええと-確かにいくつかあります:
vao=# select attname, attnum, atttypid::regtype, attisdropped::text from pg_attribute where attrelid = 'nocol'::regclass;
attname | attnum | atttypid | attisdropped
----------+--------+----------+--------------
tableoid | -7 | oid | false
cmax | -6 | cid | false
xmax | -5 | xid | false
cmin | -4 | cid | false
xmin | -3 | xid | false
ctid | -1 | tid | false
(6 rows)
したがって、これらの6つは、attisdroppedがfalseであるため、ALTER TABLEDROPCOLUMNゾンビではありません。また、これらの列のタイプ名は「id」で終わることがわかります。オブジェクト識別子タイプの下部のセクションを読むと、アイデアが得られます。もう1つの面白い観察は、-2が欠落していることです。どこでそれを失ったのだろうか-結局、テーブルを作成しただけです!うーん、どのオブジェクト識別子が私のテーブルにありませんか?定義上、私は意味します。タプル、コマンド、およびxactIDがあります。 oidのような「データベース全体のグローバル識別子」がない限り、チェックは簡単です。OIDSを使用してテーブルを作成します。
vao=# create table nocol_withoid() with oids;
CREATE TABLE
vao=# select attname, attnum, atttypid::regtype, attisdropped::text from pg_attribute where attrelid = 'nocol_withoid'::regclass;
attname | attnum | atttypid | attisdropped
----------+--------+----------+--------------
tableoid | -7 | oid | false
cmax | -6 | cid | false
xmax | -5 | xid | false
cmin | -4 | cid | false
xmin | -3 | xid | false
oid | -2 | oid | false
ctid | -1 | tid | false
(7 rows)
出来上がり!したがって、欠落している-2は確かに欠落しており、私たちはそれが好きです。使用済みデータ行にoidを使用するのは悪い考えなので、OIDSのないテーブルで遊んでいきます。
私は何を持っていますか? (oids =false)で「列テーブルなし」を作成した後、6つの属性があります。システム列を使用する必要がありますか?もしそうなら、なぜ彼らは一種の隠されているのですか?まあ-使い方は直感的ではなく、将来的に動作が変わる可能性があるため、あまり広く宣伝されていないと思います。たとえば、タプルID(ctid)を見た後、「ああ、これは一種の内部PKです」と考える人もいるかもしれません(そしてそれは一種です):
vao=# select ctid from nocol;
ctid
-------
(0,1)
(1 row)
最初の数字(ゼロ)はページ番号を表し、2番目(1)はタプル番号を表します。それらはシーケンシャルです:
vao=# insert into nocol default values;
INSERT 0 1
vao=# select ctid from nocol;
ctid
-------
(0,1)
(0,2)
(2 rows)
ただし、このシーケンスでは、その後に到着した行を定義することはできません。
vao=# alter table nocol add column i int;
ALTER TABLE
vao=# update nocol set i = substring(ctid::text from 4 for 1)::int;
UPDATE 2
vao=# select i, ctid from nocol;
i | ctid
---+-------
1 | (0,3)
2 | (0,4)
(2 rows)
ここで、(行を識別するために)列を追加し、最初のタプル番号を入力しました(両方の行が物理的に移動されたことに注意してください)
vao=# delete from nocol where ctid = '(0,3)';
DELETE 1
vao=# vacuum nocol;
VACUUM
vao=# insert into nocol default values;
INSERT 0 1
vao=# select i, ctid from nocol;
i | ctid
---+-------
| (0,1)
2 | (0,4)
(2 rows)
あはは! (イントネーションの上昇と言います)-ここで、行の1つを削除し、貧弱なテーブルの掃除機を外して、新しい行を挿入しました。結果-Postgresはスペースを節約し、解放されたスペースを再利用することを賢明に決定したため、後で追加された行は最初のページの最初のタプルにあります。
したがって、導入された行のシーケンスを取得するためにctidを使用するという考えは良くないように見えます。あるレベルまで(1つのトランザクションで作業する場合、シーケンスは残ります)、同じテーブルで新しく影響を受けた行のctidは「大きく」なります。もちろん、バキューム後(自動バキューム)、または幸運にもHOTの更新を早く取得できる場合、またはリリースされたばかりのギャップが再利用され、順番が崩れます。しかし、恐れることはありません。隠された属性は1つではなく、6つありました。
vao=# select i, ctid, xmin from nocol;
i | ctid | xmin
---+-------+-------
| (0,1) | 26211
2 | (0,4) | 26209
(2 rows)
xminを確認すると、最後に挿入された行を導入したトランザクションIDが(+2)高くなっていることがわかります(+1は削除された行でした)。したがって、順次行識別子には、まったく異なる属性を使用する可能性があります。もちろん、これは単純なことではありません。そうでなければ、そのような使用が推奨されます。 9.4より前のxmin列は、xidラップアラウンドから保護するために実際に上書きされました。なぜそんなに複雑なのですか? PostgresのMVCCは非常にスマートであり、その周りのメソッドは時間の経過とともに改善されます。もちろん、それは複雑さをもたらします。悲しいかな。システム列を避けたい人もいます。悲しいかなダブル。システムの列はかっこよく、十分に文書化されているからです。一番上の属性(oidをスキップすることを忘れないでください)はtableoidです:
vao=# select i, tableoid from nocol;
i | tableoid
---+----------
| 253952
2 | 253952
(2 rows)
今日のホワイトペーパーをダウンロードするClusterControlを使用したPostgreSQLの管理と自動化PostgreSQLの導入、監視、管理、スケーリングを行うために知っておくべきことについて学ぶホワイトペーパーをダウンロードする すべての行に同じ値があるのは役に立たないように見えますね。それでもしばらく前は、非常に人気のある属性でした。ルールと継承されたテーブルを使用してパーティションを構築していたときです。 tableoidを使用しない場合、行がどのテーブルから取得されているかをどのようにデバッグしますか?したがって、ルール、ビュー(同じルール)、またはUNIONを使用する場合、tableoid属性はソースを識別するのに役立ちます。
vao=# insert into nocol_withoid default values;
INSERT 253967 1
vao=# select ctid, tableoid from nocol union select ctid, tableoid from nocol_withoid ;
ctid | tableoid
-------+----------
(0,1) | 253952
(0,1) | 253961
(0,4) | 253952
(3 rows)
うわー、それは何でしたか? INSERT 0 1を見るのに慣れているので、psqlの出力がおかしいように見えました。ああ-本当-私はOIDでテーブルを作成し、1つの(253967)識別子を必死に無意味に使用しました!まあ-完全に無意味ではありませんが(必死ですが)-selectは同じctid(0,1)の2つの行を返します-驚くことではありません-2つのテーブルから選択し、結果を互いに追加しているので、同じctidを持つ可能性がありますそれほど低くはありません。最後に言及するのは、オブジェクト識別子タイプを使用してきれいに表示できることです。
vao=# select ctid, tableoid::regclass from nocol union select ctid, tableoid from nocol_withoid ;
ctid | tableoid
-------+---------------
(0,1) | nocol
(0,1) | nocol_withoid
(0,4) | nocol
(3 rows)
あはは! (イントネーションの上昇とともに)-これが、データソースをここに明確に固定する方法です!
最後に、もう1つの非常に人気があり、興味深い使用法です。挿入された行とアップサートされた行を定義します。
vao=# update nocol set i = 0 where i is null;
UPDATE 1
vao=# alter table nocol alter COLUMN i set not null;
ALTER TABLE
vao=# alter table nocol add constraint pk primary key (i);
ALTER TABLE
PKができたので、ONCONFLICTディレクティブを使用できます。
vao=# insert into nocol values(0),(-1) on conflict(i) do update set i = extract(epoch from now()) returning i, xmax;
i | xmax
------------+-----------
1534433974 | 26281
-1 | 0
(2 rows)
関連リソースClusterControlforPostgreSQLPostgreSQLシステムカタログの理解と読み取りPostgreSQLでのデータベースインデックスの概要 なぜそんなに幸せなの? xmaxがゼロに等しくない行が更新されたことを(ある程度の機密性を持って)伝えることができるからです。そして、それが明白だとは思わないでください。PKにunixtimeを使用したからといって、そのように見えるので、1桁の値とは実際に異なって見えます。大きなセットでそのようなONCONFLICTツイストを実行し、どの値に競合があり、どの値が競合していないかを識別する論理的な方法がないことを想像してみてください。 xmaxは、困難な時期に大量のDBAを支援しました。そして、それがどのように機能するかについての最良の説明は、ここでお勧めします-3人のディスカッション参加者(Abelisto、Erwin、Laurenz)全員に、SOに関する他のpostgresタグの質問と回答を読むことをお勧めします。
それだけです。
tableoid、xmax、xmin、およびctidは、DBAの良い友達です。 cmax、cmin、oidを侮辱しないでください-彼らも同じように良い友達です!しかし、これは小さなレビューには十分であり、今すぐキーボードから手を離したいと思います。