代码之家  ›  专栏  ›  技术社区  ›  FlySwat

SQLServer:为什么要避免使用表值用户定义函数?

  •  4
  • FlySwat  · 技术社区  · 17 年前

    我有一个相当大的查询,需要在几个存储过程中,我想把它转换成一个UDF,以便于维护(视图不起作用,这需要一系列参数),但是我曾经与之交谈过的每个人都告诉我,UDF的速度非常慢。

    虽然我不知道是什么使它们变慢了,但我可以猜到它们变慢了,但是考虑到我并没有在联接中使用这个UDF,而是返回一个表变量,我认为这不会有那么糟糕。

    所以我想问题是,我应该不惜一切代价避免UDF吗?有人能举出具体的证据表明他们的速度慢了吗?

    4 回复  |  直到 14 年前
        1
  •  4
  •   A-K    17 年前
        2
  •  3
  •   slum    17 年前

    正如您所指出的那样,(表)UDF的结果将不会与任何内容相结合,这样就不会对性能产生任何影响。

    为了解释一下为什么可以认为UDF很慢(实际上只是用了错误的方式),请考虑以下示例:

    我们有A桌和B桌,假设我们有一个像

    选择 A.COL1, A.COL2, B.Cul. 从 一 在a.aid上连接b=b.fk_aid 哪里 b.somecol=@param1和a.anothercol=@param2

    在这种情况下,SQL Server将尽其所能以其所知道的最有性能的方式返回结果。其中一个主要因素是减少磁盘读取。所以-它将使用join和where子句中的条件来计算(希望使用索引)要返回多少行。

    现在假设我们提取了一些用于重新循环返回到UDF的数据量的条件。现在-查询优化器不能再从磁盘上拉回最少的行数,它只能处理它提供的条件。简言之,在返回到主存储过程之前,总是对表UDF进行评估,并返回数据,因此,如果原始联接中存在可能导致磁盘读取次数减少的其他条件,则只有将数据拉入存储过程后,才会将其应用于数据。

    所以假设我们创建一个UDF来选择表B中与WHERE子句匹配的行。如果表B中有10万行,其中50%符合WHERE子句的条件,那么所有这些行都将返回存储过程,以便与表A进行比较。现在,如果表A中只有10%的行有匹配项,那么我们只讨论表B中5%要使用的行,但我们已经收回了50%,其中大部分是我们要使用的行,而这些行中的大多数是不想要!

    如果这被看作是胡言乱语的道歉-请让我知道!

        3
  •  0
  •   jn29098    17 年前

    你能把你的密码贴出来吗?一般来说,如果在查询的select子句中使用标量UDF,则从查询返回的每行将执行一次UDF中的语句。最好执行到表值UDF的联接,或者使用主SQL语句中的联接在UDF中执行逻辑。

        4
  •  -2
  •   CodeMonkey1313    17 年前

    你不想使用 stored procedure 而不是UDF?