这是编写SQL查询的低效方法吗?

时间:2011-10-01 23:27:56

标签: sql sql-server sql-server-2005

让我们假设我有一个观点,如下:

CREATE VIEW EmployeeView 
AS
 SELECT ID, Name, Salary(PaymentPlanID) AS Payment
 FROM Employees

用户定义的函数Salary有点贵。

如果我想做这样的事情,

SELECT *
FROM TempWorkers t
  INNER JOIN EmployeeView e ON t.ID = e.ID

Salary的每一行都会执行Employees,还是会先进行连接,然后才会对连接过滤的行进行调用?如果EmployeeView是子查询或表值函数而不是视图,我可以期待相同的行为吗?

3 个答案:

答案 0 :(得分:4)

该功能仅在相关时调用。如果您的最终选择语句不包含该字段,则根本不会调用它。如果你的最终选择指的是你表的1%,那么只会为表的1%调用它。

对于子查询/内联视图,这实际上是相同的。您可以为子查询中的字段指定函数,然后从不使用该字段,在这种情况下,函数永远不会被调用。


顺便说一句:在许多方面,标量函数确实非常昂贵。您可能能够通过将其形成为内联表值函数来降低其成本。

SELECT
  myTable.*,
  myFunction.Value
FROM
  myTable
CROSS APPLY
  myFunction(myTable.field1, myTable.field2) as myFunction

只要MyFunction是Inline(不是多语句)并且每组输入只返回一行,这通常比标量函数更好地扩展。


这与使整个视图成为表值函数略有不同,它返回许多行。

如果这样的TVF是多方的,它将为每条记录调用Salary函数。但是内联函数可以内联扩展,就像SQL宏一样,因此只需要根据需要调用Salary;喜欢这个观点。

作为TVF的一般规则,不要返回将被丢弃的记录。

答案 1 :(得分:1)

它应该只对连接的行执行Salary函数。但是你没有进一步过滤表格。如果ID是外键列而不是null,那么它将为所有行执行该函数。 实际执行计划是一个值得肯定的好地方。

答案 2 :(得分:0)

如上所述,只会为相关行调用该函数。对于您的进一步问题,并且 非常了解正在发生的事情 ,您需要通过SQL事件探查器或通过查看实际执行计划并过去来收集性能数据倍。然后测试一些理论并找出哪种理论是最佳的。