10

一部の製品の価格を格納する次のテーブル (PostgreSQL 8.3) があります。価格は別のデータベースと同期されます。基本的に、以下のほとんどのフィールド (1 つを除く) はクライアントによって更新されませんが、別の株式データベースと同期するために、時々削除および更新されます。

CREATE TABLE product_pricebands (
    template_sku varchar(20) NOT NULL,
    colourid integer REFERENCES colour (colourid) ON DELETE CASCADE,        
    currencyid integer NOT NULL REFERENCES currency (currencyid) ON DELETE CASCADE,
    siteid integer NOT NULL REFERENCES site (siteid) ON DELETE CASCADE,

    master_price numeric(10,2),

    my_custom_field boolean, 

    UNIQUE (template_sku, siteid, currencyid, colourid)
);

同期では、基本的に上記のほとんどのデータを削除しますが、my_custom_field が TRUE のデータを除きます (TRUE の場合は、クライアントが CMS を介してこのフィールドを更新したことを意味するため、このレコードを削除しないでください)。次に、数百から数千の行をテーブルに INSERT し、INSERT が失敗した場所 (つまり、(template_sku、siteid、currencyid、colorid) の組み合わせが既に存在する場所) で UPDATE を実行します。

私の質問は、主キーを作成するためにここでどのようなベスト プラクティスを適用する必要があるかということです。主キーも必要ですか?主キー = (template_sku, siteid, currencyid, colorid) を作成したかったのですが、colorid フィールドは NULL にすることができ、複合主キーで使用することはできません。

他のフォーラムの投稿で読んだことから、上記を正しく行ったと思います。明確にする必要があるだけです。

1) 必要になった場合に備えて、「シリアル」主キーを使用する必要がありますか? テーブル内の重要なデータは価格とカスタム フィールドであり、(template_sku、siteid、currencyid、colorid) の組み合わせによってのみ識別されるため、現時点ではそうではありません。

2) (template_sku, siteid, currencyid, colorid) は製品の価格を照会するために使用する組み合わせであるため、varchar である「template_sku」など、列にさらにインデックスを追加する必要がありますか? それとも、UNIQUE 制約は既に私の SELECT の適切なインデックスですか?

4

1 に答える 1

12

必要になった場合に備えて、「シリアル」主キーを使用する必要がありますか?

シリアル列が必要な場合は、後で簡単に追加できます。

ALTER TABLE product_pricebands ADD COLUMN id serial;

列には一意の値が自動的に入力されます。同じステートメントで主キーにすることもできます (まだ主キーが定義されていない場合)。

ALTER TABLE product_pricebands ADD COLUMN id serial PRIMARY KEY;

他のテーブルからテーブルを参照する場合は、そのような代理主キーを使用することをお勧めします。これは、4 つの列でリンクするのはかなり扱いにくいためです。また、JOIN を含む SELECT では速度が低下します。

いずれにせよ、主キーを定義する必要があります。null 許容列を含む UNIQUE インデックスは、完全な代替ではありません。2 つの NULL 値が同じとは見なされないため、NULL 値を含む組み合わせの重複が許可されます。トラブルの原因となります。


として

colorid フィールドは NULL にすることができます

2 つの一意のインデックスを作成したい場合があります。nullable であるため、組み合わせ(template_sku, siteid, currencyid, colourid)を にすることはできませんが、すでに持っているような制約を作成できます(インデックスを自動的に実装します)。PRIMARY KEYcolouridUNIQUE

ALTER TABLE product_pricebands ADD CONSTRAINT product_pricebands_uni_idx
UNIQUE (template_sku, siteid, currencyid, colourid)

このインデックスは、2) で言及したクエリを完全にカバーしています。
との「重複」を避けたい場合は、さらに部分的な一意のインデックスを作成します(colourid IS NULL)

CREATE UNIQUE INDEX product_pricebands_uni_null_idx
ON product_pricebands (template_sku, siteid, currencyid)
WHERE colourid IS NULL;

すべてのベースをカバーします。dba.SEの関連する回答で、その手法について詳しく説明しました。


上記の簡単な代替方法は、colouridNOT NULL を作成し、上記の代わりに主キーを作成することproduct_pricebands_uni_idxです。


また、あなたのように

基本的にほとんどのデータを削除します

補充操作では、補充操作中に不要なインデックスを削除し、後でそれらを再作成する方が高速です。すべての行を段階的に追加するよりも、最初からインデックスを作成する方が桁違いに高速です。

使用されている (必要な) インデックスをどのように知ることができますか?

  • でクエリをテストしますEXPLAIN ANALYZE
  • または、組み込みの統計を使用します。pgAdminは、選択したオブジェクトの別のタブに統計を表示します。

my_custom_field = TRUEまた、いくつかの行を選択して一時テーブル (TRUNCATEベース テーブル) に入れ、生存者を再挿入する方が速い場合もあります。外部キーが定義されているかどうかによって異なります。次のようになります。

CREATE TEMP TABLE pr_tmp AS
SELECT * FROM product_pricebands WHERE my_custom_field;

TRUNCATE product_pricebands;
INSERT INTO product_pricebands SELECT * FROM pr_tmp;

これにより、多くのバキュームが回避されます。

于 2012-05-09T14:32:37.390 に答える