SQL Azure - 如果包含大小nvarchar的列,则row_number()查询执行速度很慢

时间:2015-01-14 13:18:33

标签: performance azure azure-sql-database sqlperformance

我有以下查询(由实体框架生成标准分页。这是内部查询,我添加了TOP 438部分):

SELECT TOP 438 [Extent1].[Id] AS [Id], 
                  [Extent1].[MemberType] AS [MemberType], 
                  [Extent1].[FullName] AS [FullName], 
                  [Extent1].[Image] AS [Image], 
                  row_number() OVER (ORDER BY [Extent1].[FullName] ASC) AS [row_number]
        FROM [dbo].[ShowMembers] AS [Extent1]
        WHERE 3 =  CAST( [Extent1].[MemberType] AS int)

ShowMembers表有大约11K行,但只有438个,MemberType == 3.“Image”列的类型为nvarchar(2000),它保存CDN上图像的URL。如果我在查询中包含此列(仅在SELECT部分​​中),查询会以某种方式阻塞并生成2-30秒范围内的结果(在不同的运行中它会有所不同)。如果我注释掉该列,查询将按预期快速运行。如果我包含“图像”列,但注释掉row_number列,则查询也会按预期快速运行。

显然,我对URL的大小过于自由,所以我开始玩这个大小。我发现如果我将Image列设置为nvarchar(884),那么查询将按预期快速运行。如果我将它设置为885,它又会变慢。 这不是绑定到一列,而是绑定到SELECT语句中所有列的大小。如果我只是将大小增加一个,性能差异是显而易见的。

我不是数据库专家,所以欢迎任何建议。

PS在本地SQL Server 2012 Express中,没有性能问题。

PPS使用OFFSET运行查询0 ROWS FETCH NEXT 438行(当然没有row_count列)也很慢。

1 个答案:

答案 0 :(得分:0)

Row_number必须对所有行进行排序,以使您按所需的顺序进行操作。在结果集中添加较大的列意味着将所有列都排序,因此速度较慢/ IO会更多。顺便说一下,如果在调试此类问题时在SSMS中启用“ set statistics io on”和“ set statistics time on”,则可以看到此消息。它将使您对查询中运行时发生的IO数量和其他操作有一些了解: https://docs.microsoft.com/en-us/sql/t-sql/statements/set-statistics-io-transact-sql?view=sql-server-2017

关于如何使查询运行更快,我鼓励您考虑一些可能会稍微改变数据库架构设计的事情。首先,考虑您是否真的需要按特定顺序排序的行。如果您不需要按顺序排列东西,那么在没有row_number的情况下(以可测量的量)遍历它们会比较便宜。因此,如果您只想在概念上对每个条目进行一次迭代,则可以通过仍然是单调的,更静态的某种事物(例如,标识列)进行订购来实现。其次,如果您确实需要按排序顺序排列事物,请考虑它们是否频繁/不频繁地更改。如果不常见,则可以仅将列值计算并保留在具有所需相对顺序的每一行中(并在每次修改表时对其进行更新)。在此模型中,您可以索引新列,然后以该顺序请求内容(按查询中的顶级顺序-不需要row_number)。如果确实需要像您一样动态地计算事物,并且始终需要精确的顺序,那么最后的选择是将URL移至第二个表,并在row_number之后将其联接。这样可以避免在row_number的计算中排序“变宽”。

祝你好运