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

Sql 将复杂性封装在表变量中是最佳实践吗?,sql,sql-server,refactoring,Sql,Sql Server,Refactoring,有时我需要重构一些巨大的怪物查询,在其中我识别出一些重复 最终的结果不是完美的,而是这样的(为了交流,我在这里过于简化): 在这个例子中,我完全忽略了索引和性能(当然必须考虑到这一点),因为我想把重点放在方法上 当然,易读性得到了提高,但我不确定这是一个最佳实践还是我在雨天发现的东西 我的问题是:在重构他人编写的复杂查询时,如果您无法完全控制db模式,那么这种方法被认为是最佳实践吗 这被认为是重构的最佳实践吗 由其他人编写的复杂查询,您无法完全控制 数据库模式 在SQL Server中,使用表变

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

最终的结果不是完美的,而是这样的(为了交流,我在这里过于简化):

在这个例子中,我完全忽略了索引和性能(当然必须考虑到这一点),因为我想把重点放在方法上

当然,易读性得到了提高,但我不确定这是一个最佳实践还是我在雨天发现的东西

我的问题是:在重构他人编写的复杂查询时,如果您无法完全控制db模式,那么这种方法被认为是最佳实践吗

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

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

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

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

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

  • CTE和子查询
  • 内联表值函数
  • 观点
还有一些将查询的执行分开,并将结果集成到更大的查询中:

  • 查询加载临时表或表变量
  • 多语句表值函数
这被认为是重构的最佳实践吗 由其他人编写的复杂查询,您无法完全控制 数据库模式

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

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

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

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

  • CTE和子查询
  • 内联表值函数
  • 观点
还有一些将查询的执行分开,并将结果集成到更大的查询中:

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

考虑到表格变量的局限性,很难将其称为最佳实践!(尽管在SQL 2017中更好)您更关心的问题不应该是使用多语句TVF……重复并不一定是坏事。如果你没有解决任何问题或故意提高绩效,那么你这样做只是在创造工作和风险。人们不应该随机挑选“自己不喜欢”的工作代码,以便以某种未定义和未测量的方式“改进”它。鉴于表变量的局限性,使用它们很难被称为最佳实践!(尽管在SQL 2017中更好)您更关心的问题不应该是使用多语句TVF……重复并不一定是坏事。如果你没有解决任何问题或故意提高绩效,那么你这样做只是在创造工作和风险。人们不应该随意挑选“自己不喜欢”的工作代码,以便以某种未定义和未测量的方式“改进”它。我还担心在TVF定义中重用(复制和粘贴)表变量。我还担心在TVF定义中重用(复制和粘贴)表变量。
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