【发布时间】:2015-07-26 00:37:38
【问题描述】:
下面的整个查询运行速度非常慢。
子查询[alias Stage_1]只用了1.37分钟,返回9514条记录,但整个查询耗时20多分钟,返回2606条记录。
我可以使用 #temp 表来保存子查询以提高性能,但我不希望这样做。
查询的概述是表 WeeklySpace 内部连接到 SpaceblockName_SID 上的 Spaceblock_Name_to_PG 表,这会减少 WeeklySpace 中的结果并将 PG_Code 包含在 WeeklySpace 中的结果中。然后 WeeklySpace 在 3 个字段中与 Sales_PG_Wk 完全外联。 where 子句侧重于结果,并且可以更改。然后对子查询的结果求和。由于 group by 和 sum 过度使用,您无法在子查询中进行最终求和。
我认为问题是由于在最终求和中分组期间反复重新计算子查询。字段 SpaceblockName_SID 似乎也与导致问题有关,因为没有它,子查询中的 group by 的运行时间不会受到影响。
我已经阅读了大量建议,并尝试全部解决问题。
这些包括;
- 添加 TOP 2147483647 和 Order by 以强制中间 在子查询中和使用 CTE 实现具体化。
- 在 stage_1 之后添加连接。
- 将 SpaceblockName_SID 从 int 转换为 varchar 并再次返回
子查询和整个查询的执行计划(分为两部分,显示在代码下方)看起来相似。成本大约是我预期的完全外连接(哈希匹配)。
查询在 T-SQL 2005 上运行。
非常感谢任何帮助!
select
Cost_centre
, Fin_week
, SpaceblockName_SID
, sum(Propor_rep_SRV) as Total_SpaceblockName_SID_SRV
from
(
select
coalesce(space_side.fin_week , sales_side.fin_week) as Fin_week
,coalesce(space_side.cost_centre , sales_side.cost_Centre) as Cost_centre
,space_side.SpaceblockName_SID
,case
when space_side.SpaceblockName_SID is null
then sales_side.SalesExVAT
else sum(space_side.TLM)
/nullif(sum (sum(space_side.TLM) ) over (partition by coalesce(space_side.fin_week , sales_side.fin_week)
, coalesce(space_side.cost_centre , sales_side.cost_Centre)
, coalesce( Spaceblock_Name_to_PG.PG_Code, sales_side.PG_Code)) ,0)*sales_side.SalesExVAT
end as Propor_rep_SRV
from
WeeklySpace as space_side
INNER JOIN
Spaceblock_Name_to_PG
ON space_side.SpaceblockName_SID = Spaceblock_Name_to_PG.SpaceblockName_SID
and Spaceblock_Name_to_PG.PG_Code < 10000
full outer join
sales_pg_wk as sales_side
on space_side.fin_week = sales_side.fin_week
and space_side.Cost_Centre = sales_side.Cost_Centre
and Spaceblock_Name_to_PG.PG_code = sales_side.pg_code
where
coalesce(space_side.fin_week, sales_side.fin_week) between 201538 and 201550
and
coalesce(space_side.cost_centre, sales_side.cost_Centre) in (3, 2800)
group by
coalesce(space_side.fin_week, sales_side.fin_week)
,coalesce(space_side.cost_centre, sales_side.cost_Centre)
,coalesce( Spaceblock_Name_to_PG.PG_Code, sales_side.PG_Code)
,sales_side.SalesExVAT
,space_side.SpaceblockName_SID
) as stage_1
group by
Cost_centre
, Fin_week
, SpaceblockName_SID
执行计划左侧
执行计划右侧
【问题讨论】:
-
您说您可以解决问题,但使用临时表,但不想这样做。我能问为什么吗?除非您需要将查询设为视图,否则这似乎是一个可行的选择。我花了比我愿意承认的时间更长的时间来试图解决我需要强制实现的问题并且在几乎所有情况下都承认失败,要么决定我将使用多步表值函数并使用表变量来强制实现或者我将使用存储过程和临时表。
-
@GarethD 。感谢您花时间查看它。原来不使用临时表的原因正是你说的,所以我可以看看。第二个也是主要的原因是该代码与用于许多不同个人的报告系统一起使用。拥有临时表会给报告系统带来问题。
-
'拥有一个临时表会给报告系统带来问题。' - 如何?
-
我认为它的长处和短处是,除非this connect item 有任何结果,否则不会有一种有保证的方法来实现这一目标。像您提到的那样,有多种解决方法,您可以尝试各种提示来尝试强制急切假脱机超过惰性假脱机,但这些会根据您的表结构和统计数据而有所不同。
-
@马克辛金森。感谢您查看它。报告通过 Excel 使用 ADODB.Connection 运行。由于连接的工作方式,临时表必须是## 而不是#。因此,对于不同的用户,您必须为每个表设置不同的名称。我们已经对其他报告进行了此操作,但我们使用了注入代码,这并不理想。
标签: sql sql-server tsql sql-server-2005 subquery