背景:在Windows Server 2012 R2 Standard上使用SQL Server 2016(SP1)Standard Edition。在我们的一个生产数据库中,我们有一个名为tblEMailRequestBodyLines的表。它包含超过200万行,显示sample rows可以使您对表的总体结构有所了解(前三列构成聚簇索引)。
有关表结构的简短功能信息-SessionID代表逻辑电子邮件集,而RequestUniqueID代表该电子邮件集内的各个电子邮件。 InternalRowID是一个标识列,它定义电子邮件正文行RequestBodyLine的顺序。每封电子邮件都包含<!-详细信息开头->和<!-详细信息结尾->作为正文,以区分电子邮件内容的详细信息行的开头和结尾。始终使用SessionID和RequestUniqueID查询该表。
问题::我们想将表的当前行存储群集索引转换为列存储,并且我们在TEST环境中进行了相同的操作。 CCI转换后(查询之一)发现“开始和结束详细信息”部分的InternalROwID给出了错误的结果。基于几次测试,我认为差异是由于在列存储索引的批处理模式下处理记录的方式造成的。我已经查看了有关“列存储/批处理”模式的文档和几篇文章,但是没有任何线索。任何暗示或帮助您理解行为的“为什么”部分都将受到高度赞赏。
详细信息:这是测试案例:
SELECT *
FROM TEST_ColumnStore_tblEMailRequestBodyLines
WHERE fldSessionID = '85E55DA4-F2F4-4865-B253-B34F30AA97A9'
AND fldEMailRequestUniqueID = '61-20180809-072749.6527584'
AND fldEMailRequestBodyLine IN
(
'<!-- START OF DETAIL SECTION -->'
, '<!-- END OF DETAIL SECTION -->'
)
;
上面的查询产生结果 Test Record Rows
但是,以下查询
DECLARE @l_StartOfDetail AS BIGINT, @l_EndOfDetail AS BIGINT
SELECT @l_StartOfDetail = COALESCE(CASE
WHEN fldEMailRequestBodyLine = '<!-- START OF DETAIL SECTION -->' THEN
fldInternalRowID
END, @l_StartOfDetail)
, @l_EndOfDetail = COALESCE(CASE
WHEN fldEMailRequestBodyLine = '<!-- END OF DETAIL SECTION -->' THEN
fldInternalRowID
END, @l_EndOfDetail)
FROM TEST_ColumnStore_tblEMailRequestBodyLines
WHERE fldSessionID = '85E55DA4-F2F4-4865-B253-B34F30AA97A9'
AND fldEMailRequestUniqueID = '61-20180809-072749.6527584'
AND fldEMailRequestBodyLine IN
(
'<!-- START OF DETAIL SECTION -->'
, '<!-- END OF DETAIL SECTION -->'
)
SELECT 'Start of Detail' = @l_StartOfDetail, 'End of Detail' = @l_EndOfDetail
产生结果with incorrect InternalRowID for End Of Detail section.
请注意,我使用了COALESCE,以克服在不同批次中检索所需行的可能,从而获取所有批次中列的最终非空值。
Execution plan显示该查询是在4,877 batches.的批处理模式下串行执行的
但是,同一查询使用行存储聚簇索引生产表来生成correct results。
我有a work around创建一个临时表来保存来自CCI的批处理执行模式的输出行,然后使用临时表强制行执行模式获得正确的结果。但是,我很想知道原始查询的哪个部分使批处理执行模式产生错误的结果。
再次,感谢您阅读了很长的帖子,希望对您有所帮助或提示。