快速查询,但在VIEW中,它很慢 - 由于ROW_NUMBER

时间:2016-12-14 00:39:06

标签: sql sql-server sql-server-2016

我有一个查询,运行时,结果是即时的。

但是,我将完全相同的查询粘贴到VIEW中,结果需要6秒才能回复。

例如,

SELECT ... FROM MyTables WHERE PersonID = x

跑得快。

但是创建一个视图:

SELECT ... FROM MyTables 

然后调用视图:

SELECT * FROM MyView WHERE PersonID = x

它运行缓慢。

实际查询:

select ROW_NUMBER() over(partition by h.Id order by h.[SysStartTime]) as VersionNUmber,
      h.Id,
      fac.HIC,
      ... plus 18 other columns from the joined tables.

from   [hist].[A_View] as h
inner join [dbo].[Facilities] as fac
      on fac.Id = h.FacilityId
inner join ref.FormStatus as r_fs
      on r_fs.Id = h.FormStatusId
inner join TableA as data
      on data.Id = h.dataId
inner join Consultants as c
      on c.Id = h.ConsultantId
inner join dbo.Specialties spec
      on spec.Id = h.SpecialtyId
inner join dbo.Users modifieduser
      on modifieduser.Id = h.ModifiedByUserId
left join ref.ARefTable as r_uc
      on r_uc.Id = h.refId
cross apply [dbo].[getPersonUrn](h.PersonId, h.AnotherIdId) as PersonURN

(注意,我正在更改一些表名和列,因为我们处于相当机密的区域)

在执行视图时,我注意到97%的时间是排序(前N排序)。在查询中,这34%,但计划完全不同。

我怀疑参数嗅探,但不认为这是View的问题。

我实际上只是'修复'它,但不知道为什么。

我的选择中的第一列是ROW_NUMBER。

SELECT ROW_NUMBER() over(partition by h.Id order by h.[SysStartTime]) as` VersionNumber,

删除它,我得到即时结果。 不确定为什么,因为我订购和分区的列都已经在结果集中。

2 个答案:

答案 0 :(得分:4)

1)此处ROW_NUMBER仅适用于过滤数据:

SELECT ROW_NUMBER(), ... FROM MyTables WHERE PersonID = x

首先按PersonID过滤,然后计算ROW_NUMBER

2)此处ROW_NUMBER适用于所有数据:

CREATE VIEW MyView as
  select ROW_NUMBER(), ... FROM MyTables

SELECT * FROM MyView WHERE PersonID = x

并且仅在继续完整数据之后才应用PersonID过滤器

相同
SELECT * FROM
(SELECT ROW_NUMBER(), ... FROM MyTables
) t
WHERE t.PersonID = x

查看示例:

GO
CREATE VIEW dbo.test_view
AS
    SELECT ROW_NUMBER() OVER (ORDER BY NAME) rn, o.name, o.[object_id]
    FROM sys.objects o
GO
SET SHOWPLAN_XML ON
GO
SELECT rn, o.name, o.[object_id] FROM dbo.test_view o
WHERE OBJECT_ID < 100
GO
SELECT ROW_NUMBER() OVER (ORDER BY NAME) rn, o.name, o.[object_id] FROM sys.objects o
WHERE OBJECT_ID < 100
GO
SET SHOWPLAN_XML OFF
GO
DROP VIEW dbo.test_view
GO

视图filter操作就在最后。 所以计划实际上是不同的。

答案 1 :(得分:0)

我发现在视图中运行它时,它会用ROW_NUMBER()来计数每条记录,然后进行选择。当您在查询中运行它时,它只计算以ROW_NUMBER()返回的记录