0

24 の異なる基準に従ってテーブルの特定の行を「ルックアップ」するために、同じテーブルを 24 回自己結合する SQL クエリを実行しているため、これらすべての値を計算に使用できます。パフォーマンスはまったく問題ありませんが (テーブルにはインデックスが付けられ、結合基準は制限されています)、ここにコードの匂いがあるように感じずにはいられません。

SQL でルックアップを行うより良い方法はありますか?

(例を含めないことをお詫びします。質問を一般的な方法で表現したことを願っています)。

編集:とにかく例を試す:

CREATE TABLE key (
    pk1 int,
    pk2 int,
    pk3 int,
    PRIMARY KEY (pk1, pk2, pk3)
);

CREATE TABLE values (
    pk1 int,
    pk2 int,
    pk3 int,
    pk4 int,
    pk5 int,
    value int,
    PRIMARY KEY (pk1, pk2, pk3, pk4, pk5)
 );

 SELECT k.pk1, k.pk2, k.pk3,
        v1.value + v2.value - v3.value * (v4.value / v5.value) + ... + v24.value as result
 FROM key k
     LEFT JOIN values v1
         on v1.pk1=k.pk1
         and v1.pk2=k.pk2
         and v1.pk3=k.pk3
         and v1.pk4=100
         and v1.pk5=200

     LEFT JOIN values v2
         on v2.pk1=k.pk1
         and v2.pk2=k.pk2
         and v2.pk3=k.pk3
         and v2.pk4=400
         and v2.pk5=800

     ...

     LEFT JOIN values v24
         on v24.pk1=k.pk1
         and v24.pk2=k.pk2
         and v24.pk3=k.pk3
         and v24.pk4=900
         and v24.pk5=700;

編集 2: この構造の理由は、値テーブルが (数学的に言えば) 5 つの変数の関数を表し、事前に計算された戻り値がさまざまなパラメーターのテーブルに格納されているためです。

4

6 に答える 6

2

まず、これは自己結合ではありません。

自己結合は、テーブルがそれ自体に結合される場合です。

この例としては、階層内の親子関係や、他の人々と関係を持つ人々 (文字通り、親、子) が挙げられます。

異なる役割でテーブルを使用する場合は、それほど珍しいことではありません。

テーブル内のさまざまな値が何らかの本質的な性質で関連していない場合、タイプ コードを使用してさまざまなエンティティ ルックアップを格納する「1 つの真のルックアップ」の場合として、設計に問題が発生します。請求先住所、顧客、配送先住所、製品、およびあらゆる種類のものをすべて同じルックアップ テーブルで取得します。

データ ウェアハウスでは、特に日付または時刻のディメンションなど、さまざまな役割でディメンションを使用することもできます。

配列として使用されている列 (たとえば、first_child、second-child、third_child) に対して同じルックアップ テーブルが何度も結合された場合、これは通常、正規化に違反するため、においがします。

あなたがここに示したことに対する私の唯一の懸念は次のとおりです。

すべての値の 5 次元空間で 3 次元空間を選択するために使用されるように見えるマジック ナンバー。これら自体がどこかのテーブルで定義されていると思います (pk4、pk5、説明)。

その時点で、それぞれをビューにして読みやすくすることを検討します。

SQL Server (または同じ構成を持つ DB2) では、pk4 と pk5 でパラメーター化されたインライン テーブル値関数を使用することを実際に検討します。多くのビューの代わりに 1 つの ITVF。

しかし、これは単純にクリーンアップしただけです。クエリとテーブルの設計は、私にはかなり適切に思えます。

于 2012-06-21T20:20:13.593 に答える
1

ルックアップ テーブル全体の例を使用してこの質問に答え始めましたが、根本的な問題がはるかに大きいことに気付きました。

これらの参照を確認してください。

http://en.wikipedia.org/wiki/Entity-attribute-value_model

リレーショナル データベースのキーと値のペア

使用しているスキーマのタイプは、リレーショナル データベースの概念とは相容れないものです。キーと値の関係がないように、テーブルをフラット化してみてください。

方程式が、v1.val + v2.val / v3.val などの非正規の集計である場合 (ええ、調べないでください)、その方程式のすべての変数を単一の1 つ以上 (ただし 24 未満) の結合の後、1 つ以上のテーブルの行。

エンティティー属性値スキーマは、パフォーマンスの低下、メンテナンスの困難さ、および非常に悪臭に悩まされています。

...

それは質問に答えなかったので、ここに行きます。Icarus がコメントで提案しているようなビューを使用するか、すべてを焼き尽くして、もう少し正規化されたものを再構築します。

于 2012-06-21T19:52:22.330 に答える
1

SAS を使用しているので、データ ステップ マージを使用して少しクリーンアップできる可能性があります。次のようなもの:

data x;
  merge key 
        values(rename=value=value1 where=(pk4=100 and pk5=200))
        values(rename=value=value2 where=(pk4=400 and pk5=800))
        values(rename=value=value3 where=(pk4=900 and pk5=700))
        etc...
        ;
  by pk1 pk2 pk3;
  result = ...;
  keep pk: value: result;
run;

今、目の前に SAS がないので、すべてのコードを入力してテストするつもりはありませんが、アイデアはわかります。私には、SQLよりもずっときれいに見えると思います。データステップ マージが SQL アプローチよりも優れた代替手段を提供する場合、これは非常にまれな発見です。

于 2012-06-22T06:47:11.510 に答える
0

私があなたが探しているものを理解しているなら、それは使いやすいです:

SELECT field1, field2 from Table1 t
where exists (SELECT 1 from LookupTable l where l.fieldX=t.fieldX) 
于 2012-06-21T19:15:23.707 に答える
0

上記の回答の代わりに、次のようなこともできます。

CREATE TABLE XX AS 
SELECT k.pk1, k.pk2, k.pk3, v1.pk4, v1.pk5, v1.value
     FROM key k
 LEFT JOIN values v1
     on v1.pk1=k.pk1
     and v1.pk2=k.pk2
     and v1.pk3=k.pk3
     and ( 
          (v1.pk4=100 and v1.pk5=200) or
          (v1.pk4=400 and v1.pk5=800) or
          (v1.pk4=700 and v1.pk5=900) 
         )


proc transpose data=xx out=trans;
  by pk1 pk2 pk3;
  var value;
run;

data result;
  set trans;
  result = ...;
run;

繰り返しますが、目の前に SAS がないので、テストすることはできませんが、画像はわかると思います。この方法では、1 つの結合のみが発生し、残りの結合は追加のステップに分割されます。おそらくこれ以上インデックスを使用しないため、これがどのように機能するかはよくわかりません。そこにいくつかのアイデアを投げかけるだけです...

于 2012-06-22T07:08:38.967 に答える
0

pk4、pk5 のパラメーター ペアを num に列挙しました (実際の数値を 4*6 に置き換えました)。

CREATE TABLE zparams
        ( num INTEGER
        , pk4 INTEGER
        , pk5 INTEGER
        , PRIMARY KEY (pk4,pk5)
        , CONSTRAINT ze_other UNIQUE (num)
        );
INSERT INTO zparams(num,pk4,pk5) VALUES
 (1,1,1), (2,1,2), (3,1,3), (4,1,4), (5,1,5), (6,1,6)
, (7,2,1), (8,2,2), (9,2,3), (10,2,4), (11,2,5), (12,2,6)
, (13,3,1), (14,3,2), (15,3,3), (16,3,4), (17,3,5), (18,3,6)
, (19,4,1), (20,4,2), (21,4,3), (22,4,4), (23,4,5), (24,4,6)
        ;

CTE からの利益はかなり無駄です。

EXPLAIN ANALYZE
WITH zzz AS (
        SELECT v.pk1 AS pk1
        , v.pk2 AS pk2
        , v.pk3 AS pk3
        , p.num AS num
        , v.value AS value
        FROM zparams p
        JOIN zvalues v ON v.pk4 = p.pk4 AND v.pk5=p.pk5
        )
 SELECT k.pk1, k.pk2, k.pk3,
        v1.value + v2.value - v3.value * (v4.value / v5.value) + v24.value as result
 FROM zkeys k
     LEFT JOIN zzz v1
         ON v1.pk1=k.pk1 AND v1.pk2=k.pk2 AND v1.pk3=k.pk3
         AND v1.num=1

     LEFT JOIN zzz v2
         ON v2.pk1=k.pk1 AND v2.pk2=k.pk2 AND v2.pk3=k.pk3
         AND v2.num=2

     LEFT JOIN zzz v3 ON v3.pk1=k.pk1 AND v3.pk2=k.pk2 AND v3.pk3=k.pk3
         AND v3.num=3

     LEFT JOIN zzz v4
         ON v4.pk1=k.pk1 AND v4.pk2=k.pk2 AND v4.pk3=k.pk3
         AND v4.num=4

     LEFT JOIN zzz v5
         ON v5.pk1=k.pk1 AND v5.pk2=k.pk2 AND v5.pk3=k.pk3
         AND v5.num=5

     LEFT JOIN zzz v24
         ON v24.pk1=k.pk1 AND v24.pk2=k.pk2 AND v24.pk3=k.pk3
         AND v24.num=24
        ;

そして、100K*24 変数 (6 使用) でテストしたところ、{pk1,pk2,pk3,pk4=constant,pk5=constant} での CTE のパフォーマンス (4.5 秒) は、単純な結合 (1 秒) よりも劣っていました。しかし、少なくともそれはよりきれいに見えます。

于 2012-06-21T21:40:58.493 に答える