0

数百万行の Postgres 9.1.4 テーブルがあります。非常に小さいバージョンは次のようになります。

主人

index  location
----------------
1      A
2      C
3      B
4      C
5      C
6      A

場所フィールドの個別の値ごとにコストのかかる計算を行う必要があります。同じ場所を繰り返し処理するため、マスターテーブルからこのフィールドを使用したくありません。locationの個別の値を持つテーブルが必要で、計算の結果は計算フィールドに格納されます。

明確

index  location  calculation
------------------------------
1      A'        X
2      C'        Y
3      B'        Z

マスター個別の関係は、個別に設定された後は簡単には判断できません。計算で位置を機能させるには、少しデータ操作を行う必要があります。3 番目のテーブルが本当に必要です。これは、 distinctに入力するのとほぼ同時に作成され、distinctの各エントリをmasterの親に関連付けるのに役立ちます。

3 番目のテーブルは次のようになります。

相関

master_index  distinct_index
------------------------------
1             1
2             3
3             2
4             3
5             3
6             1

問題は、単純な SQL でこれを行う方法がわからないことです。次のようなものをクエリの先頭として使用して、distinctを設定できます。

SELECT location, array_agg(index)
FROM master
GROUP BY location;

問題は、これらの値を保持するために別個の別の配列列が必要になることです。その後、後で他のプログラムを使用して配列を解析し、相関テーブルを作成する必要があります。

これを行う簡単な方法がありませんか?

4

5 に答える 5

1

あなたが説明するのはn:mではなく1:nの関係です。correlationそのため、関係を実装するためにテーブルはまったく必要ありません。

「数百万行」のテーブルで場所を冗長に綴るのは、最適ではない設計です。正規化する必要があります。大きなテーブルは大幅に縮小します(すべてが高速になります)。列を、専用テーブルmaster.locationの新しい主キーを参照する外部キー列に置き換えます。locationそれが本来あるべき姿です。

master

master_id  loc_id  ...
-----------------
1          1       ...
2          2
3          3
4          3
5          3
6          1

location

loc_id  loc  loc_derived calc
-----------------------------
1       A    A'          X
2       C    C'          Y
3       B    B'          Z

高価な計算は、機能に依存する値の冗長ストレージを保証するようですcalcloc_derivedしかし、あなたの質問の列の計算については何もありません。locationそれほど高価ではない(そして定期的に使用される)場合は、テーブルに含めるのではなく、ビューまたは関数(生成された列)を作成する必要があります。

master通常は、との間に外部キー制約を追加して、location関係の整合性を保証します。将来的には、場所を参照する行を追加する前に、場所を追加する予定ですmaster

そこに着く方法?

  1. location代理整数主キー( )を使用してテーブルを作成しますloc_id

    CREATE TABLE location (
     loc_id serial
    ,loc text
    ,loc_derived  text  -- you really need redundant storage here?
    ,calc text          -- seems you need redundant storage here.
    );
    

    自然な主キーlocとして自分自身を使用することを勧める人がいます。私はその中にはいないので、これは悪い考えだと思います。

    • 文字列の操作とテキスト列のインデックスは、整数の処理よりもかなり低速です。
    • (中間の)重複するロケーション名に遭遇した場合、ロケーションの名前を変更するのが難しくなります。
    • 場所の名前を変更するたびに、依存するテーブルで追加の更新がトリガーされます。代理キーでは発生しません。
    • 大きなmasterテーブルは、テーブルを参照するための文字列全体ではなく、整数だけではるかに小さくなりlocationます。
  2. 新しいlocationテーブルに入力します(計算にはCTEを使用します)。

    WITH x AS (
        SELECT DISTINCT loc
        FROM master
        )
    INSERT INTO location (loc, loc_derived, calc)
    SELECT loc, some_calc(loc), some_expensive_calc(loc)
    FROM   x;
    
  3. loc_idをマスターテーブルに追加します。

    ALTER TABLE master ADD COLUMN loc_id integer;
    
  4. 列に入力しますloc_id

    UPDATE master m
    SET    loc_id = l.loc_id
    FROM   location l
    WHERE  l.loc = m.loc;
    
  5. 列を削除しますmaster.loc

    ALTER TABLE master DROP COLUMN loc;
    
  6. 真空/分析。

    VACUUM ANALYZE; 
    -- VACUUM FULL ANALYZE
    -- much slower, only to shrink the table and return disk space.
    
  7. fk制約を追加します。

    ALTER TABLE master
    ADD CONSTRAINT master_loc_id_fkey FOREIGN KEY (loc_id)
    REFERENCES location(loc_id);
    
于 2012-07-16T18:21:20.000 に答える
1

次のように「個別の」テーブルを作成できます (ただし、列としてのテーブルの名前として SQL キーワードを使用しないように注意してください)。

create table TDistinct as
    select m.location, min(index) as TDindex, <whatever> as calculation
    from master m
    group by m.location

相関テーブルを次のように作成します。

create table correlation as
    select m.index as MasterIndex, td.TDIndex
    from master m join
         TDistinct td
         on m.location = td.location

これらは機能しますが、より効率的なものが必要になる場合があります。テーブルを作成したら、効率を高めるためにインデックスを追加します。自動インクリメントされた主キーを使用して個別のテーブルを事前に作成し、それを個別のインデックスとして使用するなど、他のトリックを実行することもできます。次に、insert を使用してデータをクエリに読み込みます。

于 2012-07-16T13:53:47.763 に答える
0

私はこのSQLサーバーを実行しました。これがあなたが探しているものだと思います

クエリを使用して個別のテーブルを作成できます

select MIN("index") "index",location from tmaster
group by location 

以下のクエリによる相関表

select M."index" master_index,A."index" distinct_index
 from tmaster M left outer join 
(select MIN("index") "index",location from tmaster
group by location)A
on A.location=M.location
于 2012-07-16T13:54:13.267 に答える
0

相関関係をテーブルに入れる必要はありません。ビューまたは CTE で十分です。

DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp;
SET search_path=tmp;

-- Make some data ...
CREATE TABLE master
        ( zindex INTEGER NOT NULL PRIMARY KEY
        , location CHAR(1) NOT NULL
        );
INSERT INTO master(zindex,location) VALUES
 (1, 'A')
,(2, 'C')
,(3, 'B')
,(4, 'C')
,(5, 'C')
,(6, 'A')
        ;

    -- a view with a CTE inside
CREATE VIEW correlation AS (
        WITH zdistinct AS (
                SELECT MIN(m.zindex) AS zindex
                , m.location AS location
                FROM master m
                GROUP BY m.location
                )
        SELECT m.zindex AS master_index
                , d.zindex AS distinct_index
        FROM master m
        JOIN zdistinct d ON m.location = d.location
        );

SELECT * FROM correlation;

ちなみに、zdistinct CTE は、元の質問の「個別の」テーブルとほぼ同じです。「計算」フィールドを追加するだけで、家にいます。(最初に別のビューに入れることができます)

于 2012-07-16T14:40:13.283 に答える
0

これは、マスター テーブルと個別テーブルだけで行うことができます。個別のリスト (複数のフィールドからであっても) は、実際には外部キーの基礎です。個別のテーブルの一意の値は、マスター テーブルに戻る 1 対多の関係になります。マスター テーブルの位置データのインデックスと個別テーブルの位置データの一意のインデックスを結合すると、パフォーマンスが向上します。

于 2012-07-16T13:30:27.967 に答える