表值函数 (TVF) 与视图

发布于 2024-10-17 03:17:50 字数 62 浏览 8 评论 0原文

表值函数和视图有什么区别?有没有什么事情你可以用其中一个来做,而用另一个却很难或不可能做?或者说区别在于效率?

What's the difference between table-valued functions and views? Is there something you can do with 1 that's hard or impossible to do with the other? Or does the difference lie in efficiency?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

多彩岁月 2024-10-24 03:17:50

无参数内联 TVF 和非物化 View 非常相似。下面是我想到的一些功能差异。

视图

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  

内联 TVF

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    

多语句 TVF

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    

在运行时 视图和内联 TVF 都是内联的,并且处理方式与派生表或 CTE 类似。它们很可能不会被整体评估(甚至在某些情况下根本不会被评估)或者可能在其他情况下被多次评估 。多语句 TVF 将始终被评估并存储在返回表类型(基本上是表变量)

有时,直接参数化内联 TVF 的能力可以比针对视图的等效参数化查询产生更好的执行计划。

A parameterless inline TVF and a non materialized View are very similar. A few functional differences that spring to mind are below.

Views

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  

Inline TVFs

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    

MultiStatement TVFs

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    

At runtime Views and Inline TVFs are both inlined and treated similarly to derived tables or CTEs. They may well not be evaluated in their entirety (or even at all in some cases) or may be evaluated multiple times in others. Multistatement TVFs will always be evaluated and stored in the return table type (basically a table variable)

Occasionally the ability to parameterise inline TVFs directly can lead to a better execution plan than the equivalent parameterised query against a view.

锦爱 2024-10-24 03:17:50

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

该视图是否需要超过 2 秒才能完成,并且是否有
超过 10,000 条记录?如果是,则将其转换为 TVF。如果没有,就留下它
独自一人。

当然,该规则纯粹基于性能

对于 TVF,我可以使用CROSS APPLY,例如将其视为表,但传递特定值,例如主键

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

性能更快!

如果我有 TVF 的视图,我将不得不允许该视图返回超过 200 万行,只是为了在我的 SELECT 中返回不到 1% 的行。

值得思考的事情。

I generally have a rule of thumb when it comes to deciding whether to convert my SELECT to a VIEW or a TVF.

Does the view take longer than 2 seconds to finish and does it have
more than 10,000 records? If YES, turn it into a TVF. If not, leave it
alone.

Of course the rule is purely based on performance.

With a TVF, I can use a CROSS APPLY, for example to treat it as a table, but passing a specific value, such as the primary key.

WHERE ID = xxx, where 'xxx' is the value I pass in the SELECT.

Performance is way faster!

If I had a view of the TVF, I would have to allow the view to bring back over 2 million rows just to return less than 1% of that in my SELECTs.

Something to think about.

酒几许 2024-10-24 03:17:50

我发现当在函数的返回表上指定 PK 时,与 MultiStatement TVF 的联接比视图的表现要好得多。

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

I have found that joins with MultiStatement TVFs perform much better than Views when a PK is specified on the function's return table.

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
夜无邪 2024-10-24 03:17:50

根据我的理解,对此提供不同的看法:视图是静态SELECT语句,而TVF更接近存储过程 在创建和执行中,您利用输入变量返回动态结果集。常规(内联)TVF 不支持流量控制。如果您需要,那么您需要使用多语句 TVF。也就是说,您也可以从存储过程INSERT到表变量中,这就是TVF以更优雅的方式所做的事情,不需要<代码> EXEC权限。

从可维护性的角度来看,我更喜欢 TVF,因为我不必编写多个查询来获取各种结果,也不必从视图中进行过滤(即 SELECT * FROM [view] WHERE [conditions]) 。在 TVF 中,我可以利用索引更快地返回较小的结果集。要在视图中执行此操作,您必须预先了解查询每次将执行的操作,并硬指定过滤条件。如果您要做的只是从过去 6 个月内输入的表中选择数据子集,那么视图就可以正常工作,因为您只需编写:

SELECT [columns]
FROM [schema].[table]
WHERE [date_col] >= CAST(DATEADD(m,-6,GETDATE()) AS DATE)

为了性能,您显然希望索引 [date_col] 因此视图运行得更快。

To offer a different take on this, from my understanding: Views are static SELECT statements whereas TVFs are closer to Stored Procedures in both creation and execution in that you return a dynamic result set leveraging input variables. Regular (Inline) TVFs don't support flow control. If you need that then you need to use the Multi-Statement TVF. That said, you could also just as well INSERT into a table variable from a Stored Procedure which is what the TVF is doing in a more elegant way that doesn't need EXEC permissions.

From a maintainability perspective, I perfer TVFs as I don't have to write several queries to get various results or have to filter from a View (i.e., SELECT * FROM [view] WHERE [conditions]). In the TVF, I can leverage the indexes for returning smaller result sets faster. To do this in a view, you would have to have advance knowledge of what the query is going to do every time and hard specify the filtering conditions. If all you're going to do is select a subset of data from a table that was entered in the last 6 months, then a view would work fine as you can just write:

SELECT [columns]
FROM [schema].[table]
WHERE [date_col] >= CAST(DATEADD(m,-6,GETDATE()) AS DATE)

For performance you'd obviously want to index [date_col] so the view would run faster.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文