将复杂性封装在表变量中是最佳实践吗?

时间:2018-10-25 11:20:21

标签: sql sql-server refactoring

有时候我需要重构一些巨大的怪物查询,以便在其中识别出一些重复。

最终结果是一些东西,虽然不是完美的,但是却是这样(在这里,我为了通信目的过于简化):

DECLARE @CustomersEligibleForDiscount TABLE
(
CustomerID int,
Rate int
)

insert into @CustomersEligibleForDiscount
SELECT STATEMENT to populate table variable

DECLARE @ActiveCampaigns TABLE
(
CampaignID int,
Expiration date,
Prize decimal(4,2)
)

insert into @ActiveCampaigns
SELECT STATEMENT to populate table variable


DECLARE @OneOfTheManyOhterTables TABLE
(
TABLE DEFINIION
)
insert into @OneOfTheManyOhterTables
SELECT STATEMENT to populate table variable

-- GIven the table variables above i can write the main query in this was

SELECT
 FIELDS
FROM @CustomersEligibleForDiscount CEFD
JOIN @@OneOfTheManyOhterTables OT ON ...
[...]
JOIN @ActiveCampaigns ON...

-- In this way the main query is much more readable

-- THen since those table variables contain the "business logic" it happens that i need to use them
-- in stored function that return tables so i redeclare all the variables (may be i just need a subset)
-- in the stored function again, example:
CREATE FUNCTION dbo.sf_GiveMeATable(@CustomerID int,@LastLogin DATETIME)
RETURNS @ResultsTAble TABLE
(
    ID int,
    CODE nvarchar(50),
    DESCR nvarchar(120)
)

BEGIN

  DECLARE @CustomersEligibleForDiscount TABLE
  (
  CustomerID int,
  Rate int 
  )
  insert into @CustomersEligibleForDiscount
  SELECT STATEMENT to populate table variable

  DECLARE @OneOfTheManyOhterTables TABLE
  (
  TABLE DEFINIION  
  )
  insert into @OneOfTheManyOhterTables
  SELECT STATEMENT to populate table variable

  DO SOMETHING TO POPULATE @ResultsTAble
  RETURN

END

在此示例中,我完全忽略了索引和性能(当然必须考虑),因为我想专注于该方法。

当然可以提高可读性,但是我不确定这是最佳实践还是我在下雨天发现的某些东西。

我的问题是:当重构其他人编写的复杂查询并且您没有对数据库模式的完全控制权时,这种方法是否被认为是最佳实践?

1 个答案:

答案 0 :(得分:3)

  

这是重构的最佳实践吗?   由他人编写的复杂查询,您无法完全控制   数据库模式?

在SQL Server中,使用表变量或临时表来缓冲复杂查询中的中间结果是一种非常常见的模式。临时表可能是首选,因为它们对索引和统计信息有更好的支持。

从您应该始终或通常这样做的意义上来说,这不是“最佳实践”。基本模式是使用通用表表达式在逻辑上分离子查询,并将复杂查询转换为转换的逻辑“管道”。如果发现查询过于复杂,或者查询计划不符合您的喜好,那么通常可以提前运行一个或多个子查询并加载临时表或表变量。

在TSQL中,表值函数可用于封装查询,就像在CTE(或子查询)和临时表之间进行选择一样,您可以选择TVF是否只是重用查询表达式的方式,还是与封闭查询分开执行。多语句表值函数将获得其自己的执行计划,而内联表值函数将被集成到封闭查询的查询计划中。

因此,在封装查询的方法中,有一些在优化查询表达式之前将其集成到包含的查询中:

  • CTE和子查询
  • 内联表值函数
  • 观看次数

还有一些将查询的执行分开并将结果集成到较大的查询中:

  • 查询加载临时表或表变量
  • 多语句表值函数