1

私は4つの非常に大きなテーブルを持っています。それらをX、A、B、Cと呼びましょう。

次のように、Xからさらに2つのテーブルX1とX2を作成します。

テーブルXのレコードrについて考えてみます。rがテーブルA、B、Cの少なくとも1つに対応するレコードを持っている場合、それをX1に入れます。それ以外の場合はX2に入れます。

(rに対応するレコードがA、B、またはCにあると判断するにはどうすればよいですか?rのいくつかのフィールドをA、B、またはCのレコードのいくつかのフィールドと比較します。フィールドはA、B、またはCで異なる場合があります。また、rをA、B、またはCのレコードと照合するための基準が複数ある場合があります。おそらく、この部分は主な問題とは関係ありません。)

両方のオプションがあります。X、A、B、CをOracleテーブルまたはSASデータセットとして使用できます。

この問題を解決する最も効率的な方法は何ですか?

よろしく、

4

2 に答える 2

1

Tartaglia の答えはかなり近いですが、おそらく 1 つのステップで行う方が簡単です。

data x1 x2;
merge x(in=x) a(in=found keep=id) b(in=found keep=id) c(in=found keep=id);
by id;
if x and found then output x1;
else if x then output x2;
run;

'found' と 'x' が元のデータセットの変数ではないことを確認してください。それ以外 の場合は別のものを使用してください。唯一の複雑な要因は、a、b、c の ID 以外の変数が必要な場合です。その場合、複数の一致シナリオがある場合に適切な変数を確実に取得する方法を検討する必要があります。また、4 つのテーブルすべてを並べ替える必要があります (時間がかかる場合があります)。

もう 1 つの SAS ソリューション: ハッシュ テーブル。これには、データセットを並べ替える必要はありませ。データセットがまだ整っていない場合、これはおそらく高速です。ただし、テーブル a、b、および c のすべてをメモリに格納するのに十分なメモリが必要であり、これらのデータセットのサイズによっては制約を受ける可能性があります。また、a、b、c が x に対して小さい場合は、それらが同様のサイズである場合よりも優れています。これは、defineData を使用して、単なるリターン コードではなく、a/b/c からデータを生成するように操作できますが、a、b、c の 2 つ (または3つすべて)。

data abc/view=abc;
set a b c;
keep id;
run;

data x1 x2;
if _n_ = 1 then do;
 declare hash abc(dataset:"abc");
 abc.defineKey("id");
 abc.defineDone();
 call missing(id);
end;
set x;
rc = abc.find();
if rc=0 then output x1;
else output x2;
run;

オラクルでそれを行うには、tartagliaのソリューションに近いことを行うと思います.3つの「一致」テーブルを作成し、それらを結合して(結合で重複を削除します)、xマイナスとしてx2を作成しますx1テーブル。IE (これは SAS の PROC SQL で機能しますが、oracle が except とまったく同じかどうかはわかりません):

create table x1 as
  select x.* from x,a where x.id=a.id
  union
  select x.* from x,b where x.id=b.id
  union
  select x.* from x,c where x.id=c.id
;
create table x2 as
  select * from x except select * from x1;

SASを使用してこれらをテストしました(SQLソリューションを含みます。これは、Oracleの方が少し優れている可能性がありますが、同様の順序である必要があります-ただし、Oracleサーバーがsasサーバーよりも高速な場合は、状況が変わる可能性があります)。

5e7 レコードのデータセット「x」と、かなりオーバーラップする 3 つのデータセット「a」「b」「c」を使用します (おそらく、レコードの 25% 程度が 2 つ以上のデータセットにあり、84% が 1 つ以上のデータセットにあります)。それぞれのレコードが 1.5e7 から 3e7 の間 (具体的には、すべて奇数、1 つが 3 の倍数、もう 1 つが 4 の倍数) の場合、SQL ソリューションはソート アンド マージ中に処理に 5 分以上かかりました。ソリューションのソートに約 2.5 分、マージに 0.5 分かかったので、合計で約 3 分かかりました。これは、データセットが並べ替えられて作成されたため、少し誇張されている可能性があるため、並べ替え自体が多少高速になった可能性があります (ただし、SQL は、データセットが並べ替えられていることからいくらか得られます)。

これは、5e7 データセット x の約 5 秒の書き込み時間と比較されます。

ハッシュ ソリューションは、全体で ~6e7 のレコード データセット abc を持つ私のラップトップのメモリに収まらないため、一部を合計 ~2e7 に縮小しました (したがって、1 から 2e7 までのオッズ、次に 2e7 から 4e7 までの 3 の倍数、次に、4e7 から 6e7 までの 4 の倍数) ですが、x には 5e7 レコードが含まれています。ハッシュ ソリューションは合計で 1:41 かかりました。同様の時間がかかったソート アンド マージ ソリューションと比較して、そのほとんどは x のソート (約 1 分) と結果のデータセットのマージ/書き出し (約 30 分) でした。 . 小さいデータセットはメモリ内で並べ替えられますが、大きいデータセットは並べ替えられないため、これは大きなデータセットを並べ替えるよりもはるかに高速でした。SQL ソリューションは、これらのデータセットで約 4 分だったので、それでもかなり遅くなりました。

于 2012-12-27T14:36:01.353 に答える
0

私があなたを正しく理解していれば、次のようなことができます:

一致を見つけたい変数のデータセット X と A をマージします。レコード形式 A に一致する X からのレコードを X1 に出力し、一致しないレコードを X2 に出力します。

サンプル データセット X と A を扱っているとします。

data x;
input id some_value $;
datalines;
1 a
2 b
3 c
4 d
5 e
run;

data a;
input id some_value $ some_value_2 $;
datalines;
1 a x
4 d v
5 g u
run;

これで、次のようにマージできます。

data x1_a x2_a;
merge x(in=table_x) a(in=table_a keep=id some_value);
by id some_value;
if table_x = 1 and table_a = 1 then output x1_a;
if table_x = 1 and table_a = 0 then output x2_a;
run;

データセット B および C に対して繰り返します。データセット B および C との一致に異なるルールがある場合は、 byandステートメントを変更します。また、 and の名前をtoなどに変更して、それらが上書きされないようにします。keepx1_ax2_ax1_b

すべてのx1_テーブルをX1追加すると、質問で説明されているデータセットが得られます (重複に対処する必要がある場合があります)。

すべてのx2_テーブルを追加し、個別の行を数えます。比較対象の初期データセットと同じ回数 (この場合は A、B、C の 3 つ) 表示される行が保持されます。

于 2012-12-27T14:25:23.080 に答える