我有一个视图(实际上,它是一个表值函数,但观察到的行为在两者中是相同的)内连接和左外连接其他几个表。当我使用类似于
的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 /视图中执行字符串格式化或无论如何,表现很棒。在查看执行计划时,它没有给我一个线索来看待这个问题,这就是我最初忽略它的原因。
答案 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。