0

「レガシー」から現在へのクロスオーバーポイントで、計算された値の複雑なセットを返す必要があるシナリオに遭遇しました。

長い話を短くするために、私はこのようなものを持っています...

with someofit as
(
   select id, col1, col2, col3 from table1
)

select someofit.*, 
  case when id < @lastLegacyId then
    (select ... from table2 where something = id) as 'bla'
   ,(select ... from table2 where something = id) as 'foo'
   ,(select ... from table2 where something = id) as 'bar'
  else
    (select ... from table3 where something = id) as 'bla'
   ,(select ... from table3 where something = id) as 'foo'
   ,(select ... from table3 where something = id) as 'bar'
  end
from someofit

ここに問題はありません...サブ選択ごとにそのケースチェックを常に実行したくはありませんが、同時にその条件が適用される場合は、関連するケースブロック内のすべての選択が必要です。

これを行うためのよりスマートな方法はありますか?

適切なオブジェクト指向言語を使用している場合は、次のようなものを使用します...

var common = GetCommonSuff()

foreach (object item in common)
{
   if(item.id <= lastLegacyId)
   {
      AppendLegacyValuesTo(item);
   }
   else
   {
      AppendCurrentValuesTo(item);
   }
}

最初は、すべてユニオンを使用して2つの完全な選択を実行しようとしましたが、効率/評価する行数のため、これはあまりうまく機能しません。

サブセレクションは、テーブル2または3のいずれかでIDが一致する以外の条件が満たされているが、それらのテーブルに数百万の行が含まれている可能性がある合計行数を探しています。

cteは2つの理由で使用されます...

まず、テーブル1から行のみを取得します。興味があるので、すぐに、それぞれの場合にサブ選択の一部のみを実行します。

次に、テーブル1の1回のルックアップで一般的なものを返します。

何か案は?

編集1:

状況へのいくつかのコンテキスト...

「imports」というテーブル(上記の表1)があります。これは、ファイル(csvなど)からデータを取得し、レコードをデータベースにプルするインポートジョブを表しています。

次に、「ステップ」と呼ばれるテーブルがあります。これは、実行する処理/クリーニングルールを表し、各レコードには、sproc名とルールに関するその他の情報が含まれています。

次に、特定のインポート「ImportSteps」のルールを表す結合テーブルがあります(上記の表2-現在のデータの場合)。これには、「rowsaffected」列とインポートIDが含まれます。

したがって、現在のジョブの場合、私のSQLは非常に単純です...

importsjoinimportstepsから123456を選択します

古いレガシーのものについては、テーブル3を確認する必要があります...テーブル3は保持テーブルであり、これまでにインポートされたすべてのレコードが含まれ、各行にはインポートIDがあり、各行にはキー値が含まれます。

ステップIDがyであるインポートIDxのテーブル2で影響を受ける新しいデータ行で、私の値が返されます。

レガシーデータでは、colz=何かを保持している行を数える必要があります

約20のインポートに関するデータが必要であり、このデータはmvc Webアプリの「datagrid」にバインドされています(違いがある場合)

私が使用するcteは、いくつかのパラメーターを介して、それらのパラメーターが開始レコードと終了レコード(インポートIDの順序)を表す「現在関心のある20im」を決定します。

私の最大の問題は、テーブルを保持することです...それは巨大です..個々のジョブはそれ自体で500k以上のレコードを含むことが知られており、このテーブルは何年ものインポートされた行を保持するので、そのテーブルでのルックアップをできるだけ速くする必要がありますできるだけ少なくします。

編集2:

実際の解決策(suedoコードのみ)..。

-- declare and populate the subset to reduce reads on the big holding table
declare table @holding ( ... )
insert into @holding
select .. from holding

select 
   ... common stuff from inner select in "from" below
   ... bunch of ...
   case when id < @legacy then (select getNewValue(id, stepid))
   else (select x from @holding where id = ID and ... ) end as 'bla'
from

(
   select ROW_NUMBER() over (order by importid desc) as 'RowNum'
   , ...
) as I
-- this bit handles the paging
where RowNum >= @StartIndex
and   RowNum < @EndIndex 

私はまだそれをもっときれいにすることができると確信していますが、請求書の解決策のように見えた私の元のクエリは実行時間で約45秒でした、これは約7です

4

2 に答える 2

3

サブクエリは単一のスカラー値を返す必要があると思いますよね?この点は、LEFTJOINが結果を乗算しないことを保証するものであるため重要です。

;with someofit as
(
   select id, col1, col2, col3 from table1
)

select someofit.*, 
  bla = coalesce(t2.col1, t3.col1),
  foo = coalesce(t2.col2, t3.col2),
  bar = coalesce(t2.bar, t3.bar)
from someofit
left join table2 t2 on t2.something=someofit.id and somefit.id < @lastLegacyId
left join table3 t3 on t3.something=someofit.id and somefit.id >= @lastLegacyId 

id >= @lastLegacyIdidがnull許容ではないと仮定して、条件の補足として使用していることに注意してください。そうである場合は、そこにIsNullが必要ですsomefit.id >= isnull(@lastLegacyId,somefit.id)


質問を編集しても、これがOO構文のほぼ直訳であるという事実は変わりません。

foreach (object item in common)  --> "from someofit"
{
   if(item.id <= lastLegacyId)      --> the precondition to the t2 join
   {
      AppendLegacyValuesTo(item);   --> putting t2.x as first argument of coalesce
   }
   else                              --> sql would normally join to both tables
                                     --> hence we need an explicit complement
                                     --> condition as an "else" clause
   {
      AppendCurrentValuesTo(item);    --> putting t3.x as 2nd argument
                                      --> tbh, the order doesn't matter since t2/t3
                                      --> are mutually exclusive
   }
}

function AppendCurrentValuesTo     --> the correlation between t2/t3 to someofit.id

さて、実際にこれを試しても問題が解決しない場合は、どこで問題が発生したのかを知りたいと思います。

于 2012-09-28T09:05:21.413 に答える
1

2つのテーブルの間に競合するIDがないことを知っていると仮定すると、次のようなことができます(DB2構文、それは私が知っていることですが、似ているはずです):

with combined_tables as (
    select ... as id, ... as bla, ...as bar, ... as foo from table 2
    union all
    select ... as id, ... as bla, ...as bar, ... as foo from table 3
)
select someofit.*, combined_ids.bla, combined_ids.foo, combined_ids.bar
    from someofit
    join combined_tables on someofit.id = combined_tables.id

IDが重複するような場合は、combined_tables()セクション内で処理できます。

于 2012-09-28T09:05:56.737 に答える