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 有两个原因...

首先,它只从表 1 中提取我感兴趣的行,因此我只在每种情况下只做一小部分子选择。

其次,它在表 1 上的一次查找中返回常见的东西

有任何想法吗?

编辑 1:

这种情况的一些背景......

我有一个名为“imports”的表(上面的表 1),它代表一个导入作业,我们从文件(csv 或类似文件)中获取数据并将记录拉入数据库。

然后我有一个名为“步骤”的表,它代表我们经历的处理/清理规则,每条记录都包含一个存储过程名称和一堆关于规则的其他内容。

然后有一个连接表,表示特定导入“ImportSteps”的规则(上面的表 2 - 用于当前数据),其中包含“rowsaffected”列和导入 ID

所以对于当前的工作,我的 sql 非常简单......

从导入中选择 123 456 加入导入步骤

对于较旧的遗留东西,但是我必须查看表 3 ...表 3 是保存表,它包含曾经导入的每条记录,每一行都有一个导入 ID,每一行都包含键值。

在表 2 上影响到导入 id x 的新数据行上,其中步骤 id 为 y 将返回我的值。

在遗留数据上,我必须计算其中 col z = something 的行数

我需要大约 20 个导入的数据,并且这些数据绑定到我的 mvc Web 应用程序上的“datagrid”(如果这有什么不同的话)

我使用的 cte 通过一些参数确定“当前 20 个我感兴趣”这些参数代表开始和结束记录(按导入 ID 排序)。

我最大的问题是持有表......它是巨大的......众所周知,个别工作本身包含 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

我认为子查询必须返回单个标量值,对吗?这一点很重要,因为它确保了 LEFT JOIN 不会使结果相乘。

;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 >= @lastLegacyId通过假设 id 不可为空来用作条件的补充。如果是,您需要一个 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

假设您知道两个表之间没有冲突的 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 这样的情况,你可以在 combine_tables() 部分中处理它

于 2012-09-28T09:05:56.737 回答