表值函数(TVF) vs. 视图(View)

93

表值函数和视图有什么区别?使用表值函数可能做到的事情,在视图中是否难以或不可能实现?还是两者之间的区别在于效率?

3个回答

151

一个没有参数的内联表值函数和一个非物化的视图非常相似。下面是我想到的一些功能上的差异。

视图

Accepts Parameters               - No
Expanded out by Optimiser        - Yes
Can be Materialized in advance   - Yes (through indexed views)
Is Updatable                     - Yes 
Can contain Multiple Statements  - No
Can have triggers                - Yes
Can use side-effecting operator  - Yes  

内联表值函数

Accepts Parameters               - Yes
Expanded out by Optimiser        - Yes
Can be Materialized in advance   - No
Is Updatable                     - Yes
Can contain Multiple Statements  - No
Can have triggers                - No
Can use side-effecting operator  - No    

多语句表值函数

Accepts Parameters               - Yes
Expanded out by Optimiser        - No
Can be Materialized in advance   - No
Is Updatable                     - No
Can contain Multiple Statements  - Yes
Can have triggers                - No
Can use side-effecting operator  - No    

在运行时,视图和内联表值函数(Inline TVF)都会被内联处理,并且类似于派生表或公共表表达式(CTE)。它们可能不会完全评估(甚至在某些情况下根本不评估),在其他情况下可能会被多次评估。多语句表值函数(Multistatement TVF)始终会被评估并存储在返回表类型中(基本上是一个表变量)。

有时直接对内联表值函数进行参数化比针对视图执行等效的参数化查询可以获得更好的执行计划。


4
"Is Updatable" 是 TVF 的一个属性,表示该表值函数可以被更新。 - Royi Namir
3
@RoyiNamir - 内联 TVF 可以用于更新基表,类似于视图。 - Martin Smith
你的意思是 TVF 可以从自身更新返回的表格吗? - Royi Namir
15
CREATE TABLE T(C INT);EXEC('CREATE FUNCTION F () RETURNS TABLE AS RETURN (SELECT * FROM T)');INSERT INTO F() VALUES(1);SELECT * FROM T;创建一个名为T的表,其中包含一个整数列C。然后执行一段动态SQL语句,该语句创建一个名为F的函数,该函数返回T表的全部内容。接着将值1插入到F函数中,并从表T中查询所有行并返回结果。 - Martin Smith
另外还有两个不同之处,即with check optionVIEW_METADATA - Martin Smith
非常好的答案,不仅适用于初学者。 - Pரதீப்

10

当我需要决定是将我的SELECT转换为VIEW还是TVF时,我通常有一个经验法则。

视图是否需要超过2秒才能完成,并且记录数超过10,000条? 如果是,将其转换为TVF。 否则,请不要改变它。

当然,这个规则纯粹基于性能

使用TVF,例如使用CROSS APPLY,可以像处理表一样处理它,但传递特定的值,例如主键

WHERE ID = xxx,其中'xxx'是我在SELECT中传递的值。

性能更快!

如果我有一个视图或TVF,我必须允许视图带回超过2百万行,只返回我的SELECTs中不到1%的内容。

值得思考。


2

我发现当函数的返回表上指定了PK时,与MultiStatement TVFs连接比视图执行效果要好得多。

CREATE FUNCTION [FORMREQS].[fnGetFormsStatus] ()
RETURNS

/* Create a PK using two of the columns */
@Indexed TABLE (
    [OrgID] [char](8) NOT NULL,
    [PkgID] [int] NOT NULL,
    [FormID] varchar(5) NOT NULL,
    PRIMARY KEY CLUSTERED(OrgID, PkgID) 
)
AS
BEGIN
INSERT @Indexed SELECT OrgID, PkgID, FormID FROM FormsTable

RETURN

END

2
而视图也是如此。事实上,建立一个表格会导致函数运行得更慢。一个内联函数,即只有一个RETURNS子句的函数不需要创建任何临时表,因此它将至少运行两倍快。可能会更快,因为优化器将能够将其查询包含在优化中。 - Panagiotis Kanavos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接