2

我应该为每个别名表达式使用单独的 CROSS APPLY 还是在可能的情况下在同一个 CROSS APPLY 中定义多个表达式?

我正在重构代码中生成的许多非常复杂的 SQL 查询(通常是四五页长的十几个 JOIN)。通常它们嵌套了五六个查询,因为某些部分在不同情况下被重用。嵌套查询的一个典型原因是一个查询提取一些值,执行计算,并为该值分配一个别名。然后封闭查询使用别名值等进行进一步计算。这是必要的,因为别名表达式只能在外部查询中引用,而不能在定义它的查询中的其他地方引用。(另一种方法,也存在于代码中,是在整个查询中重复相同的冗长子表达式十几次。)

为了简化这个意大利面条 SQL,我开始使用 CROSS APPLY 折叠这些伸缩查询。通过使用 CROSS APPLY,我可以分配一个别名并在同一查询的其他地方使用它。请注意,我的 CROSS APPLY 子句都没有通过子选择或调用 UDF 引入新表。

一开始,我把很多表达式放在同一个 CROSS APPLY 里。但是,我的代码需要模块化。在不同的情况下将需要不同的字段,因为用户可以为过滤器选择字段,并且我们为不同的列生成相似的统计信息,因此创建许多相似的查询,它们彼此之间只有一点点不同。由于有些字段建立在其他字段之上,而有些则依赖于查询中前面定义的某些 JOIN,因此我不能将所有内容放在同一个 CROSS APPLY 中。因此,CROSS APPLY 的数量可能会有所不同。

此外,从中提取的某些字段被新别名遮蔽并重新定义(通常用于删除 NULL、提供默认值等)。因此,当在其他地方引用 CROSS APPLY 定义的字段时,需要将 CROSS APPLY 的表别名指定为消除歧义。

这样做的结果是,我需要一种合乎逻辑的方式来命名我的 CROSS APPLY,并且我关心性能。如果 CROSS APPLY 的数量发生变化,那么如果 CROSS APPLY 使用简单的计数器进行编号(例如,computed1、computed2 等),那么给定字段可能会看到其名称引用从 computed3.[FIELD NAME] 更改为 computed4.[FIELD NAME],它在查询的其余部分产生连锁反应,可能是通过调用不同的 C# 过程来组装的。这是一个维护问题。

我正在考虑的替代方法是将每个计算表达式放在单独的 CROSS APPLY 中,并且 CROSS APPLY 的名称将从表达式的别名派生。例如:

使用一个 CROSS APPLY:

CROSS APPLY (
    SELECT
          [TIV_BLDG] = (CASE [COVERAGE] WHEN 'TIV_BLDG' THEN VALUEAMT ELSE 0 END)

        , [TIV_OSTR] = (CASE [COVERAGE] WHEN 'TIV_OSTR' THEN VALUEAMT ELSE 0 END)

        , [TIV_CONT] = (CASE [COVERAGE] WHEN 'TIV_CONT' THEN VALUEAMT ELSE 0 END)

        , [TIV_TIME] = (CASE [COVERAGE] WHEN 'TIV_TIME' THEN VALUEAMT ELSE 0 END)

) computed2

使用四个 CROSS APPLY:

CROSS APPLY (SELECT [TIV_BLDG] = (CASE [COVERAGE] WHEN 'TIV_BLDG' THEN VALUEAMT ELSE 0 END)) AS [TIV_BLDG_COMP]

CROSS APPLY (SELECT [TIV_OSTR] = (CASE [COVERAGE] WHEN 'TIV_OSTR' THEN VALUEAMT ELSE 0 END)) AS [TIV_OSTR_COMP]

CROSS APPLY (SELECT [TIV_CONT] = (CASE [COVERAGE] WHEN 'TIV_CONT' THEN VALUEAMT ELSE 0 END)) AS [TIV_CONT_COMP]

CROSS APPLY (SELECT [TIV_TIME] = (CASE [COVERAGE] WHEN 'TIV_TIME' THEN VALUEAMT ELSE 0 END)) AS [TIV_TIME_COMP]

如果我使用这种多重 CROSS APPLY 方法,我可以轻松生成在添加新应用或删除它们时不会更改的名称,并且我可以在引用字段的代码中预测表别名将是什么。但是,这意味着更多的 CROSS APPLY 语句。性能影响是什么?有没有更好的方法来做到这一点,使用 CROSS APPLY 或其他一些 SQL Server 功能?(我不需要它是跨数据库的,所以只有 Microsoft 的功能就可以了。)

4

1 回答 1

0

如果存在性能劣势,则必须在查询执行的编译阶段。由于执行计划在查询执行的第二秒被缓存,因此不会有性能损失。

SQL Server 可以看穿 CROSS APPLY 并将它们转换为简单的、堆叠的“计算标量”。

另一个潜在问题可能是查询的大小。不确定在 AST 节点或连接数量方面是否存在任何相关限制(我猜 CROSS APPLY 在涉及内部限制时算作连接)。

除了这些问题,我认为 CROSS APPLYs 是一个非常好的和快速的解决方案。

于 2012-07-10T20:33:57.913 回答