在select子句中包含nvarchar(max)列会大大增加执行时间

时间:2017-10-03 09:04:40

标签: sql sql-server sql-server-2012 database-tuning-advisor

我有一个简单的表,由列和索引组成,如下所示。

Columns

Indexes

这是我在推荐sql数据库引擎优化顾问时创建的索引。它包含所有列。

CREATE NONCLUSTERED INDEX [_dta_index_PROPOSAL_PROCESS_12_13243102__K2_K7_K1_3_4_5_6_8_9_10] ON [dbo].[PROPOSAL_PROCESS]
(
    [PROPOSAL_ID] ASC,
    [IS_DELETED] ASC,
    [ID] ASC
)
INCLUDE (   [CREATOR_USER_ID],
    [CREATION_TIME],
    [LAST_UPDATER_USER_ID],
    [LAST_UPDATE_TIME],
    [CURRENT_PROPOSAL_OBJECT],
    [INTERFACTORING_XML],
    [OMDM_OUTPUT_XML]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

每当我添加图片中检查的列时,执行时间就会严重增加。这是我的测试结果。

如果我不包含上述列。

SET STATISTICS IO ON
SET STATISTICS TIME ON
CHECKPOINT; 
GO 
DBCC DROPCLEANBUFFERS; 
GO  
DECLARE @DynamicFilterParam_000001 bit = 0,
        @DynamicFilterParam_000002 bit = null,
        @EntityKeyValue1 int = 4419;    
SELECT 
    [Extent1].[ID] AS [ID], 
    --[Extent1].[CURRENT_PROPOSAL_OBJECT] AS [CURRENT_PROPOSAL_OBJECT], 
    --[Extent1].[INTERFACTORING_XML] AS [INTERFACTORING_XML], 
    --[Extent1].[OMDM_OUTPUT_XML] AS [OMDM_OUTPUT_XML], 
    [Extent1].[PROPOSAL_ID] AS [PROPOSAL_ID], 
    [Extent1].[CREATOR_USER_ID] AS [CREATOR_USER_ID], 
    [Extent1].[CREATION_TIME] AS [CREATION_TIME], 
    [Extent1].[LAST_UPDATER_USER_ID] AS [LAST_UPDATER_USER_ID], 
    [Extent1].[LAST_UPDATE_TIME] AS [LAST_UPDATE_TIME], 
    [Extent1].[IS_DELETED] AS [IS_DELETED]
    FROM [dbo].[PROPOSAL_PROCESS] AS [Extent1]
    WHERE (([Extent1].[IS_DELETED] = @DynamicFilterParam_000001) ) AND ([Extent1].[PROPOSAL_ID] = @EntityKeyValue1);

(54行(s)受影响) 表' PROPOSAL_PROCESS'。扫描计数1,逻辑读取58,物理读取2,预读读取55,lob逻辑读取0,lob物理读取0,lob预读读取0。

(1行受影响)

SQL Server执行时间:     CPU时间= 31 ms,已用时间= 16 ms。 SQL Server解析和编译时间:     CPU时间= 0 ms,已用时间= 0 ms。

SQL Server执行时间:    CPU时间= 0 ms,经过时间= 0 ms。

如果我将CURRENT_PROPOSAL_OBJECT添加到上一个查询的select子句

(54行(s)受影响) 表' PROPOSAL_PROCESS'。扫描计数1,逻辑读取58,物理读取2,预读读取55,lob逻辑读取0,lob物理读取0,lob预读读取0。

(1行受影响)

SQL Server执行时间:     CPU时间= 0 ms,已用时间= 545 ms。 SQL Server解析和编译时间:     CPU时间= 0 ms,已用时间= 0 ms。

如果我添加INTERFACTORING_XML以选择先前查询的子句

(54行(s)受影响) 表' PROPOSAL_PROCESS'。扫描计数1,逻辑读取58,物理读取2,预读读取55,lob逻辑读取1822,lob物理读取376,lob预读读取0。

(1行受影响)

SQL Server执行时间:     CPU时间= 47 ms,已用时间= 2415 ms。 SQL Server解析和编译时间:     CPU时间= 0 ms,已用时间= 0 ms。

如果我将CURRENT_PROPOSAL_OBJECT添加到上一个查询的select子句

(54行(s)受影响) 表' PROPOSAL_PROCESS'。扫描计数1,逻辑读取58,物理读取2,预读读取55,lob逻辑读取5048,lob物理读取944,lob预读读取0。

(1行受影响)

SQL Server执行时间:     CPU时间= 47 ms,已用时间= 6912 ms。 SQL Server解析和编译时间:     CPU时间= 0 ms,已用时间= 0 ms。

所以在一天结束的时候我面临6912毫秒秒。这种糟糕表现的原因是什么?

我错过了创建一些索引吗?这是因为糟糕的设计源于将大尺寸的nvarchar放在同一张桌子上?

提前致谢

编辑:Here是重新生成问题的脚本。我试图在sql-fiddle上创建相同的问题,但它甚至没有插入一行。

编辑2:如果我在select子句中包含所有列,并且只提供另一个使查询返回2行的提议ID,则执行时间通常大约保持在100 ms。查询执行时间变得越来越糟,这取决于返回的增加rows.No与索引的连接。

3 个答案:

答案 0 :(得分:1)

NVARCHAR(max)是旧ntext数据类型的替代。

ntext将始终将其信息存储为行外的BLOB。在可能的情况下,NVARCHAR(max)将尝试将信息存储在该行中。如果由于尺寸不合适,那么它会将文本存储在BLOB中。

SQL Server将处理从BLOB到可读nvarchar文本的转换,但不是免费的。每次SQL Server必须离开行时,都会产生额外的开销。

调优顾问实际上是在告诉你这个。比较第一个查询(0)上的lob(大对象)读取次数,以及后面的参数和引用nvarchar(max)字段的数量。

答案 1 :(得分:1)

不要把调整顾问当作福音,它为你提供了为完成工作而生成的计划的建议,通常可以应用更好的索引。

如果有效地使表的大小加倍,则所有列上的非聚簇索引。因为您将拥有聚簇索引(实际表)和非聚簇索引中的副本。如果要插入表格,这将使写入量增加一倍。

如果您从一个表开始选择,但只是在索引键的where子句中有两列,那么Proposal_IDIs_Deleted上的索引。使用SET STATISTICS IO ON和执行计划,看看它在做什么然后你可以在那里玩。

Richie Rump的统计解析器:http://statisticsparser.com/用于读取统计信息的输出

答案 2 :(得分:1)

  

我错过了创建一些索引吗?这是因为糟糕的设计源于将大尺寸的nvarchar放在同一张桌子上?

在所有情况下,我都可以看到经过的时间不一致..但整体cpu时间保持相对较低..

如果我的查询以1毫秒开始并且需要8000毫秒,这是查询/经过时间的总时间,但在此CPU时间内只能是10毫秒..

这似乎发生在你的情况下,尝试运行查询,你会看到查询等待cpu ..

最后,我没有看到你的查询和索引的任何问题,我相信你看到的执行时间是由于等待统计数据