【问题标题】:Optimization - is union the best way to go in this case?优化 - 在这种情况下,联合是最好的方法吗?
【发布时间】:2015-09-06 14:44:57
【问题描述】:

我有一个每天从外部数据源更新的数据集(示例)。然后将这些数据与其他一些内部数据(Scale)组合并形成一个新表。

示例包含一些有时可能是错误的数字。我在单独的表格中登记了哪些基金和日期的数据不正确(错误)。我希望从另一个我知道是正确的日期获取数据并将其用作代理。

我编写了一小段代码来说明我的问题。所以 - 目的是最终得到一个完整的表格,其中包含不同公司投资组合中所有单一投资(即我查看投资基金)的历史数据。如果某个基金的任何数据出现错误,则该基金的数据应取自另一个日期(不一定是之前的日期)。即使不正确的数据被另一个日期的数据替换,缩放比例也应该保持不变。

我想了很多,发现我似乎想出解决方案的唯一方法是 UNION 两种不同的选择,一种是原始数据不包括数据不正确的资金,另一种是替换数据。但我觉得应该有一种更简单的方法来实现我所需要的。我的原始数据同时存在于表格和视图中,并且像现在一样庞大且有点慢,因此我有兴趣找到创建新表格的最有效方法。

提前致谢! 线

CREATE TABLE Example(
   MarketDate   datetime NOT NULL,
   FundName VARCHAR(20) NOT NULL,
   SecurityName VARCHAR(48) NOT NULL,
   MarketValue  FLOAT(25),
   Risk  FLOAT(25),
);

CREATE TABLE tblScale(
   MarketDate   datetime NOT NULL,
   Entity VARCHAR (20)   NOT NULL,
   FundName VARCHAR(48) NOT NULL,
   Scale  FLOAT(25),
);

CREATE TABLE Errors(
   MarketDate datetime NOT NULL,
   RiskDate datetime NOT NULL,
   FundName VARCHAR(48) NOT NULL,
);


INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-15', 'Fund1', 'Bond1', 2000.00, 5 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-15', 'Fund1', 'Bond2', 1500.00, 4);
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-15', 'Fund1', 'Bond3', 1300.00, 3 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-15', 'Fund1', 'Bond4', 300.00, 109 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-15', 'Fund1', 'Bond5', 700.00, 400 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-15', 'Fund1', 'Bond6', 600.00, 350 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-14', 'Fund1', 'Bond1', 2100.00, 5.1 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-14', 'Fund1', 'Bond2', 1400.00, 4.2 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-14', 'Fund1', 'Bond3', 1330.00, 3.9 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-14', 'Fund1', 'Bond4', 200.00, 2.1 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-14', 'Fund1', 'Bond5', 400.00, 2.5 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-14', 'Fund1', 'Bond6', 500.00, 2.6 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-15', 'Fund2', 'Bond7', 1800.00, 3.5 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-15', 'Fund2', 'Bond8', 1900.00, 4.5);
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-15', 'Fund2', 'Bond9', 1300.00, 3 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-15', 'Fund2', 'Bond10', 350.00, 2.1 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-14', 'Fund2', 'Bond7', 1700.00, 3.4 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-14', 'Fund2', 'Bond8', 1810.00, 4.2 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-14', 'Fund2', 'Bond9', 1330.00, 3.4 );
INSERT INTO Example (MarketDate,FundName,SecurityName,MarketValue,Risk) VALUES ('2015-06-14', 'Fund2', 'Bond10', 320.00, 2.0 );

INSERT INTO tblScale (MarketDate,Entity,FundName,Scale) VALUES ('2015-06-15', 'Comp1', 'Fund1', 0.76 );
INSERT INTO tblScale (MarketDate,Entity,FundName,Scale) VALUES ('2015-06-15', 'Comp2', 'Fund1', 0.10 );
INSERT INTO tblScale (MarketDate,Entity,FundName,Scale) VALUES ('2015-06-15', 'Comp3', 'Fund1', 0.14 );
INSERT INTO tblScale (MarketDate,Entity,FundName,Scale) VALUES ('2015-06-15', 'Comp1', 'Fund2', 0.30 );
INSERT INTO tblScale (MarketDate,Entity,FundName,Scale) VALUES ('2015-06-15', 'Comp2', 'Fund2', 0.35 );
INSERT INTO tblScale (MarketDate,Entity,FundName,Scale) VALUES ('2015-06-15', 'Comp3', 'Fund2', 0.25 );
INSERT INTO tblScale (MarketDate,Entity,FundName,Scale) VALUES ('2015-06-14', 'Comp1', 'Fund1', 0.75 );
INSERT INTO tblScale (MarketDate,Entity,FundName,Scale) VALUES ('2015-06-14', 'Comp2', 'Fund1', 0.10 );
INSERT INTO tblScale (MarketDate,Entity,FundName,Scale) VALUES ('2015-06-14', 'Comp3', 'Fund1', 0.15 );
INSERT INTO tblScale (MarketDate,Entity,FundName,Scale) VALUES ('2015-06-14', 'Comp1', 'Fund2', 0.30 );
INSERT INTO tblScale (MarketDate,Entity,FundName,Scale) VALUES ('2015-06-14', 'Comp2', 'Fund2', 0.35 );
INSERT INTO tblScale (MarketDate,Entity,FundName,Scale) VALUES ('2015-06-14', 'Comp3', 'Fund2', 0.25 );

INSERT INTO Errors (MarketDate,RiskDate,FundName) VALUES ('2015-06-15', '2015-06-14', 'Fund1' );

Declare @Todate as datetime = '2015-06-15';

select data.MarketDate as MarketDate
       ,data.MarketDate as RiskDate
       ,scale.Entity 
       ,data.SecurityName
       ,sum(data.MarketValue)*scale.Scale as MV
from Example data
inner join tblScale scale
on data.MarketDate=scale.MarketDate
and data.FundName=scale.FundName
where data.MarketDate=@Todate
and data.FundName not in (select FundName from Errors where MarketDate=@Todate)
group by data.MarketDate,scale.Entity,data.SecurityName,scale.Scale

union

select  @Todate as MarketDate
       ,data.MarketDate as RiskDate
       ,scale.Entity 
       ,data.SecurityName
       ,sum(data.MarketValue)*scale.Scale as MV
from (select @Todate as Today,* from Example
      where fundname in (select fundname from Errors where marketdate=@todate)
      and marketdate in (select riskdate from Errors where marketdate=@todate)
     ) data
inner join tblScale scale
on data.FundName=scale.FundName
and data.Today=scale.MarketDate
where scale.MarketDate=@Todate
group by data.MarketDate
         ,scale.Entity
         ,data.SecurityName
         ,scale.Scale
         ,scale.MarketDate

【问题讨论】:

  • 如果您不需要删除可能来自不同选择的重复行,请改用“union all”
  • 是的,你的权利@JamesZ。由于他使用了@todate 变量,该变量用于排除第一条语句中的行,因此它们根本不会重复。
  • 请编辑您的帖子以包含各种表的索引和此查询的解释计划
  • @JamesZ,注意“联合所有” - 永远不会出现重复行。
  • @TheMadDBS,我对sql编程不是很有经验,所以当你提到“解释计划”时,我不确定你的意思。它只是在代码部分的解释吗?

标签: sql-server join optimization union


【解决方案1】:

首先,您可以使用UNION ALL,这将省略重复检查。这会快得多。

另一个建议是您的第一个SELECT 中的IN()。如果您的子查询返回许多行,这可能会导致运行时间过长。

我建议从这里重新设计它:

select data.MarketDate as MarketDate
       ,data.MarketDate as RiskDate
       ,scale.Entity 
       ,data.SecurityName
       ,sum(data.MarketValue)*scale.Scale as MV
from Example data
INNER join tblScale scale
on data.MarketDate=scale.MarketDate
and data.FundName=scale.FundName
where data.MarketDate=@Todate
and data.FundName not in (select FundName from Errors where MarketDate=@Todate)
group by data.MarketDate,scale.Entity,data.SecurityName,scale.Scale

对此LEFT JOIN 包括IS NULL 过滤器:

select data.MarketDate as MarketDate
       ,data.MarketDate as RiskDate
       ,scale.Entity 
       ,data.SecurityName
       ,sum(data.MarketValue)*scale.Scale as MV
from Example data
inner join tblScale scale
on data.MarketDate=scale.MarketDate
and data.FundName=scale.FundName
LEFT JOIN (select FundName from Errors where MarketDate=@Todate) as fundname
        ON data.FundName = fundname.FundName
where data.MarketDate=@Todate
and fundname.Fundname IS NULL
group by data.MarketDate,scale.Entity,data.SecurityName,scale.Scale

【讨论】:

  • 感谢您的建议,但我很抱歉说我不太了解它们...您加入了 Errors 中出现的 FundNames,但我想在我的第一个选择,因为这些是 @Todate 上的示例中的数据不正确的那些。添加“fundname.FundName IS NULL”背后的想法是什么?因为在错误表中永远不会有一个为 NULL 的注册。
  • 忘了说当我运行上面建议的选择时,它返回空。
  • 抱歉,我现在没有太多时间。但顺便提一下,我在第二次选择时出错了。我现在已经更正了。你可以再试试第二个。
  • 我自己就应该意识到这一点! :) 感谢您的意见。
  • 没问题。由于您标记为答案,结果不再为空? :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多