【问题标题】:Query fast, but when in a VIEW, it's slow - due to ROW_NUMBER查询速度快,但在 VIEW 中查询速度很慢 - 由于 ROW_NUMBER
【发布时间】:2016-12-14 00:39:06
【问题描述】:

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

但是,我将完全相同的查询粘贴到 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% 的时间都在排序(Top N Sort)中。在查询中,那 34%,但计划完全不同。

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

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

我选择的第一列是 ROW_NUMBER。

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

删除它,我会立即获得结果。 不知道为什么,因为我排序和分区的列都已经在结果集中了。

【问题讨论】:

  • 你检查过执行计划吗?您可以从工具栏中包含执行计划。运行查询后,您可以点击执行计划选项卡并查看发生了什么。
  • 我这样做了,这就是我报告“97% 的时间,它在一个排序(前 N 个排序)中”的方式。
  • 您使用的是 top 还是 order by 子句?你能发布实际的查询、表格脚本和执行计划吗?您是否都在 ssms 中运行?
  • 添加了实际的视图查询。
  • 您在即时运行的查询中是否有row_number()?只需确保您将苹果与苹果进行比较。

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


【解决方案1】:

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 中,操作已经结束。 所以计划实际上是不同的。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-30
      • 2018-11-16
      • 1970-01-01
      • 2023-03-13
      • 2019-03-10
      • 1970-01-01
      • 2016-06-08
      • 1970-01-01
      相关资源
      最近更新 更多