AJA*_*JAr 0 t-sql sql-server stored-functions set-returning-functions
今天,工作中的首席 DBA 说我不应该使用 ITVF 来完全包装视图,但从我的基本基准来看,我对此表示怀疑。看起来 SQL Server 只是在查询时对它实际需要的列进行排序(基于函数的请求)。我这么说是因为我发现下面两个示例的执行时间非常相似。
uf_GetCustomersByCity_A在此示例中,我创建了一个 ITVF,它执行 a 操作SELECT *,返回一个已过滤的CustomerView。
CREATE FUNCTION [dbo].[uf_GetCustomersByCity_A] (@idCity INT)
RETURNS TABLE
AS RETURN
SELECT CustView.*
FROM [dbo].[CustomerView] CustView
WHERE CustView.idCity = @idCity
GO
Run Code Online (Sandbox Code Playgroud)
uf_GetCustomersByCity_BCREATE FUNCTION [dbo].[uf_GetCustomersByCity_B] (@idCity INT)
RETURNS TABLE
AS RETURN
SELECT CustView.idCustomer
, CustView.cFullName
, CustView.cCityName
, CustView.fBalance
FROM [dbo].[CustomerView] CustView
WHERE CustView.idCity = @idCity
GO
Run Code Online (Sandbox Code Playgroud)
我的问题是,这是否是一个有效的观察结果,或者只是长时间调试的副作用(假设 SQL Server 通过使用进行优化)。在视图中提供所需的所有内容而不是在 ITVF 中专门指定每一列具有很大的价值。
因此,两者都工作得很好,在 4-5 秒内产量约为 500k 行(注意:有一些复杂的子句会导致漫长的执行时间,这些示例很难说明这里的目的)。该视图有大约 70 或 80 列,其中许多都是内联格式化或操作的。
-- Around 500k rows in ~3-4 seconds:
SELECT idCustomer, cCityName
FROM [dbo].[uf_GetCustomersByCity_A](93)
-- Around 500k rows, again ~3-4 seconds:
SELECT idCustomer, cCityName
FROM [dbo].[uf_GetCustomersByCity_B](93)
Run Code Online (Sandbox Code Playgroud)
开发盒上的性能相同,但目前没有其他人使用它。假设这是和cFullName的串联,而返回的结果与存储时完全相同。添加到查询的影响明显低于,这让我相信我注意到的不是 SSMS 的交付时间。cGivenNamecFamilyNamecCityNamecCityNamecFullName
-- Around 500k rows, ~6 seconds:
SELECT idCustomer, cFullName
FROM [dbo].[uf_GetCustomersByCity_A](93)
-- Around 500k rows, ~6 seconds:
SELECT idCustomer, cFullName
FROM [dbo].[uf_GetCustomersByCity_B](93)
Run Code Online (Sandbox Code Playgroud)
我的想法是,如果SELECT *ITVF 内很重要,那么它将花费大量时间来确定它不使用的列的值。SELECT *从我制定的快速基准来看,当我通过包装整个视图而不是一次指定一列,从本质上重申视图的结构时,我根本没有看到太大的差异。我的预感在这里有效吗?
in是内联的i——如你所知。这意味着,引擎将尝试找到最佳执行计划,就好像该语句直接写入查询中一样。iTVF
从这个角度来看,无论使用还是使用应该没有什么区别
SELECT * FROM YourView WHERE idCity=@idCity
Run Code Online (Sandbox Code Playgroud)
或者
SELECT * FROM YourITVF(@idCity)
Run Code Online (Sandbox Code Playgroud)
引擎应该足够聪明,可以只处理所需的列,但一般来说,最好使用固定的列列表。(请参阅@a_horse_with_no_name 评论中的链接。)
提示:当您包装视图(如您想要的那样)时,SELECT * FROM ...您应该记住,如果您更改视图,则必须重新编译此 iTVF。
问题可能是,引擎无法解决深层嵌套结构,并且最终可能找不到最佳计划(甚至可能看不到,最终结果中不需要昂贵的计算列)。
如果您的视图是基于子视图构建的,并且这些子视图是从子子视图、其他 iTVF 等构建的,这将导致次优计划。
几天前,我不得不调整一个缓慢的视图,结果是一个具有 9(!) 个调用级别的视图,覆盖了视图中的视图中的视图......以及许多计算列等等。引擎再也无法穿过这片丛林了。
简而言之:
| 归档时间: |
|
| 查看次数: |
2318 次 |
| 最近记录: |