SQL反对视图的条款

时间:2010-03-22 04:05:11

标签: sql sql-server

我有一个视图(实际上,它是一个表值函数,但观察到的行为在两者中是相同的)内连接和左外连接其他几个表。当我使用类似于

的where子句查询此视图时
SELECT *
FROM [v_MyView]
WHERE [Name] like '%Doe, John%'

...查询非常慢,但如果我执行以下操作...

SELECT *
FROM [v_MyView]
WHERE [ID] in 
(
    SELECT [ID]
    FROM [v_MyView]
    WHERE [Name] like '%Doe, John%'
)

它快得多。第一个查询至少需要2分钟才能返回,如果不是更长,第二个查询将在不到5秒的时间内返回。

有关如何改善这一点的任何建议?如果我将整个命令作为一个SQL语句运行(不使用视图),它也非常快。我相信这个结果是因为视图应该像一个表一样,如果一个视图有OUTER JOINS,GROUP BYS或TOP ##,如果在执行视图之后在vs之前解释了where子句,结果可能不同。我的问题是为什么SQL不能将我的第一个查询优化为与第二个查询一样高效的东西?

修改

所以,我正在努力想出一个例子,并打算使用普遍可用的AdventureWorks数据库作为主干。复制我的情况(这实际上是在调试其他人开发的慢进程,但不是全部吗?)我无法得到相同的结果。进一步研究我正在调试的查询,我意识到问题可能与广泛使用用户定义的标量值函数有关。大量使用“GetDisplayName”函数,根据您传入的值,它将格式化lastname,firstname或firstname lastname等。如果我只是省略该函数并在主查询/ TVF /视图中执行字符串格式化或无论如何,表现很棒。在查看执行计划时,它没有给我一个线索来看待这个问题,这就是我最初忽略它的原因。

2 个答案:

答案 0 :(得分:1)

虽然我不是SQL大师,但很可能是因为在第二个查询中你只选择了一个使其更快的列,其次是ID列似乎是某个键并因此被索引。这可能是第二种方式更快的原因。

第一次查询:

SELECT * FROM [v_MyView] WHERE [Name] like '%Doe, John%'

第二次查询:

SELECT * FROM [v_MyView] WHERE [ID] in  
(SELECT [ID] FROM [v_MyView] WHERE [Name] like '%Doe, John%')

答案 1 :(得分:1)

标量UDF很可能是问题所在。一旦他们进入您的查询,您就会有一个RBAR执行计划。如果它们在SELECT中,但是如果它们被用在WHERE或JOIN子句中,那是可以忍受的......

很遗憾,因为它们非常有用,但它们是大型SELECT中的性能杀手,我建议尝试将UDF重写为表值,或者尽可能重写查询以避免UDF。