KB3067257 - 修正:2014 SQL Server 在叢集欄位商店索引查詢時出現部分結果

套用到
SQL Server 2014 Developer - duplicate (do not use) SQL Server 2014 Enterprise - duplicate (do not use) SQL Server 2014 Standard - duplicate (do not use)

本文討論在 Microsoft SQL Server 2014 中查詢叢集欄位儲存索引時所發生的問題。 本文提供了這個問題的 解決方案

摘要

當你在 Microsoft SQL Server 2014 中使用掃描叢集欄位儲存索引的查詢時,在極少數情況下,你可能會收到部分查詢結果。

當執行以下操作時,會發生這個問題。

步驟 1

Transact-SQL 語句 [INSERT 或 BULK-INSERT] 將資料插入具有叢集欄位儲存索引的資料表。 在此操作期間,適用以下條件:

  • 當 Transact-SQL 語句達到列群組閾值時,會關閉具有區段 S1 的列群組 R1。
  • 區段 S1 指向本地字典 D1。
  • 該語句繼續將資料列插入到新的列群 R2。
  • 當行群 R1 封閉時,本地字典 D1 不必也關閉。 如果字典 D1 還有空間,你可以保留空間,然後重新用於新的列群 R2。

步驟 2

若 Transact-SQL 語句在關閉新列群組 R2 前異常結束或被取消,則適用以下條件:

  • 欄位儲存的元資料變更發生在獨立於外部交易提交的子交易中。
  • 此時,列群組 R1 在系統資料表中以「建構中」或「不可見」狀態持續存在,而區段 S1 則參考字典 D1。
  • 系統表中沒有為字典 D1 建立任何列。 這是因為 Transact-SQL 陳述句從未有機會關閉現有的列。 因此,現有的爭議依然存在。

步驟 3

在典型情況下,若元組移動器背景任務在 Transact-SQL 陳述句結束後開始,背景任務會移除隱形的列群 R1 和段 S1。 如果現在啟動一個新的 Transact-SQL 語句,並建立了列群組 R3,該列群中有新的區段 S3,需要新的本地字典,你就不能重複使用字典 D1 的內部 ID。 這是因為欄位儲存的記憶體狀態會記錄所使用的字典 ID。 因此,S3段將參考新的字典D2。

注意,此步驟中的條件是常見條件。 因此,不會發生腐敗。

步驟 4

如果SQL Server在元組移動任務 (生效前失去字典 D1 的記憶體狀態,且執行步驟 3) 中描述的動作,則本文所述問題就會出現。

記事​​

  • 此事件發生原因包括以下任一:

    • SQL Server 會經歷記憶體過載,字典 D1 的記憶體內容會被逐出記憶體。
    • SQL Server 的實例會被重新啟動。
    • 包含叢集欄位儲存索引的資料庫會先離線,然後再重新上線。
  • 當這些事件發生任一且 SQL Server 重新載入記憶體結構時,就不會有字典 D1 及其內部 ID 存在的紀錄。 這是因為當 Transact-SQL 陳述式結束或合併時,字典 D1 並未保留在系統資料表中。

  • 如果元組移動器背景任務從此開始,則不會發生錯誤,因為步驟 3 中描述的條件仍然適用。

  • 若在元組移動者背景任務開始 (前建立新的列群組 R3,) SQL Server 會為新的字典 D1 分配相同的內部 ID,並參考字典 D1 作為列群 R3 的段碼。

  • 當元組移動者背景任務在前一個動作後啟動時,會丟棄隱形的行群 R1 及其段 S1,以及新的字典 D1。 這是因為元組移動器認為新字典 D1 與 S1 所參考的原始字典 D1 是相同的。

    注意:當發生此狀況時,無法查詢列組 R3 的內容。

解決方式

此問題首次在以下 SQL Server 累積更新中被修正:

Cumulative Update 1 for SQL Server 2014 SP1
        
         累積更新8 for SQL Server 2014
此問題的修正也包含在以下GDR) 更新 (通用發行版中:

SQL Server 2014 QFE 安全更新  
此更新包含累積更新 8、此重要修正及必要的 MS15-058 安全更新。

SQL Server 2014 GDR 安全更新  
此更新包含此重要修正及累積安全修正,涵蓋 MS15-058。

Nonsecurity Update for SQL Server 2014 Service Pack 1 GDR  
這次更新只包含這個重要的修正。

關於 SQL Server 的累積更新

每次新的 SQL Server 累積更新都包含了之前累積更新中包含的所有熱修補與安全修補。 請參閱 SQL Server 最新的累積更新:

      

更多資訊

錯誤訊息在目前受影響的資料庫中,若在套用此修正後執行 DBCC CHECKDB,您將收到以下錯誤訊息:

注意

Msg 5289,16層,州1,1號線
表格 't' 上的叢集欄位儲存索引 'cci' 包含一個或多個與字典中資料值不符的資料值。 從備份中還原資料。

在目前受影響的資料庫中,當你執行查詢掃描受影響的資料表時,套用此修正後會收到以下錯誤訊息:

注意

Msg 5288,16層,州1,1號線
欄位儲存索引包含一個或多個與字典中資料值不符的資料值。 請查詢DBCC CHECKDB以獲得更多資訊。

如果你收到這些錯誤,你可以透過大量匯出未受影響欄位/列群組的資料,然後在放置或建立叢集欄位儲存索引後重新載入資料,來保存未損壞的資料。 你應該啟用 Trace flag 10207,以抑制 5288 錯誤,並回復跳過損壞列組的舊行為。

注意:錯誤訊息 5288 與 5289 是針對具有段 S3 的行群 R3 產生的。 追蹤旗標 10207 用於擷取行組 R3 中不受缺少字典 D1 影響的區段。

查詢受影響的資料庫為判斷包含欄位儲存索引的資料庫是否已受此問題影響,請執行以下查詢:

select  
       object_name(i.object_id) as table_name, 
       i.name as index_name, 
       p.partition_number, 
       count(distinct s.segment_id) as damaged_rowgroups 
from 
       sys.indexes i 
       join sys.partitions p on p.object_id = i.object_id and p.index_id = i.index_id 
       join sys.column_store_row_groups g on g.object_id = i.object_id and g.index_id = i.index_id and g.partition_number = p.partition_number 
       join sys.column_store_segments s on s.partition_id = p.partition_id and s.segment_id = g.row_group_id 
where  
       i.type in (5, 6) 
       and s.secondary_dictionary_id <> -1  
       and g.state_description = 'COMPRESSED' 
       and s.secondary_dictionary_id not in 
       ( 
              select dictionary_id from sys.column_store_dictionaries d 
              where d.hobt_id = p.hobt_id and d.column_id = s.column_id 
       ) 
group by  
       object_name(i.object_id), 
       i.name, 
       p.partition_number 

記事​​

  • 你必須對每個包含欄位儲存索引的資料庫執行這個查詢,該資料庫正在執行 SQL Server。 結果集為空表示資料庫未受影響。

  • 在沒有活動會建立新列群組或改變現有列群組狀態的期間執行此查詢。 例如,以下活動可以修改列群的狀態:index build、index reorganize、bulk insert、tuple mover 壓縮 delta store。

    在執行查詢前,你可以使用追蹤旗標 634 來停用背景元組移動任務。 使用此指令停用背景任務:DBCC TRACEON ( 634,-1 ) 。 查詢執行結束後,請記得使用指令重新啟用背景任務:DBCC TRACEOFF ( 634, -1 ) 。

    同時也要確保在查詢執行時,沒有 BULK INSERT/BCP/SELECT-INTO 指令將資料插入使用欄位儲存索引的資料表。

    建議使用這些步驟以防止查詢回傳誤報。

狀態

Microsoft 已確認這是「適用對象」一節中列出的 Microsoft 產品中的問題。