我有一个具有以下结构的表:
ItemID int
ItemType char(1)
Language char(2)
Localization char(2)
Literal nvarchar(4000)
它用于将特定的文本翻译ItemID
成Literal
一个。该Literal
列可能包含HTML
标签。对于一组特定的查询,HTML
需要删除这些标签,并且因为清理是使用 SQL CLR 对数千行进行的,所以我不希望在读取时执行此类操作。
所以,我添加了一个这样的持久列:
ALTER TABLE [dbo].[table]
ADD [LiteralSanitized] AS NULLIF(CAST(LTRIM(RTRIM([dbo].[fn_Utils_RemoveAllHtmlTags] ([Literal]))) AS NVARCHAR(4000)), '') PERSISTED;
该表只有一个索引(主键),定义如下:
ItemID, ItemType, Language, Localization
所以查询速度更快,但我看到这个表有一些额外的读取:
Scan count - 2 vs 12,230
Logical reads - 3,234 vs 43,472
由于该列,这可能是正常的,因为现在我读取了更多数据。所以,我添加了以下索引:
(ItemID ASC, ItemType ASC, Language ASC, Localization ASC) INCLUDE ([LiteralSanitized])
但它不被引擎使用。所以,我尝试强制引擎使用它:
UPDATE #temp
SET [QuestionText] = PSGQ.[LiteralSanitized]
FROM #temp PQD
INNER JOIN [dbo].[table_with_translations] PSGQ WITH(INDEX = [the_new_index])
ON PQD.[ProtoQuestionID] = PSGQ.[ItemID]
WHERE PSGQ.[ItemType] = 'Q'
AND PSGQ.[Language] = @language
AND RTRIM(PSGQ.[Localization]) = ''
AND PSGQ.[LiteralSanitized] IS NOT NULL;
但引擎正在执行以下操作:
- 执行索引扫描(在我的新索引上)
- 然后使用聚集索引执行嵌套循环和键查找
- 提取
literal
列
如果我的列是Persisted
,为什么引擎继续尝试返回该Literal
列,因为它甚至不需要?
您的问题最有可能的答案在于 Paul White 的这篇博文:正确持久的计算列
听起来很像 SQL Server 决定它宁愿重新计算列值而不是从磁盘读取它。
正如 Paul 所提到的,一种解决方案是使用跟踪标志 176 来禁用计算列扩展。