sql - 在 select 子句中包含 nvarchar(max) 列会显着增加执行时间

标签 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

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

如果我不包含上述任何列。

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 行受影响) 表“PROPOSAL_PROCESS”。扫描计数 1,逻辑读取 58,物理读取 2,预读读取 55,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。

(1 行受影响)

SQL Server 执行时间: CPU 时间 = 31 毫秒,运行时间 = 16 毫秒。 SQL Server 解析和编译时间: CPU 时间 = 0 毫秒,运行时间 = 0 毫秒。

SQL Server 执行时间: CPU 时间 = 0 毫秒,运行时间 = 0 毫秒。

如果我将 CURRENT_PROPOSAL_OBJECT 添加到先前查询的 select 子句中

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

(1 行受影响)

SQL Server 执行时间: CPU 时间 = 0 毫秒,运行时间 = 545 毫秒。 SQL Server 解析和编译时间: CPU 时间 = 0 毫秒,运行时间 = 0 毫秒。

如果我将 INTERFACTORING_XML 添加到先前查询的 select 子句

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

(1 行受影响)

SQL Server 执行时间: CPU 时间 = 47 毫秒,运行时间 = 2415 毫秒。 SQL Server 解析和编译时间: CPU 时间 = 0 毫秒,运行时间 = 0 毫秒。

如果我将 CURRENT_PROPOSAL_OBJECT 添加到先前查询的 select 子句中

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

(1 行受影响)

SQL Server 执行时间: CPU 时间 = 47 毫秒,运行时间 = 6912 毫秒。 SQL Server 解析和编译时间: CPU 时间 = 0 毫秒,运行时间 = 0 毫秒。

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

我是否缺少创建一些索引?这是由于将大尺寸的 nvarchar 放在同一个表中而导致的糟糕设计的结果吗?

提前致谢

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

编辑 2:如果我在 select 子句中包含所有列,并且只给出另一个使查询返回 2 行的提案 Id,执行时间通常保持在大约 100 毫秒。查询执行时间变得越来越糟,具体取决于返回的增加行。与索引无关。

最佳答案

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

ntext 总是将其信息存储为行外的 BLOB。在可能的情况下,NVARCHAR(max) 将尝试将信息存储在行中。如果它不能因为大小,那么它会将文本存储在 BLOB 中。

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

调优顾问实际上是在告诉您这一点。将您的第一个查询 (0) 中的 lob(大对象)读取次数与随后的查询和引用 nvarchar(max) 字段的次数进行比较。

关于sql - 在 select 子句中包含 nvarchar(max) 列会显着增加执行时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46540933/

相关文章:

asp.net - 将空值插入日期字段?

sql-server - 配置 ADP 应用程序以使用不同的数据库...?

c# - 处理由 asp.net 页面触发的频繁数据库写入

sql-server - SSIS 重新排列同一列中的全名

sql - 列出一台服务器中所有数据库的所有触发器

sql - 用空格替换引号之间的逗号

sql - Django : I have a save() which is failing. 如何查看生成的 SQL?

sql - 为什么column = NULL不返回任何行?

sql - 在 PostgreSQL 表中生成测试数据

sql-server - 使用内连接 sql 查询进行计数