KB3067257 - การแก้ไข: ผลลัพธ์บางส่วนในคิวรีของดัชนี Clustered ColumnStore ใน SQL Server 2014

นำไปใช้กับ
SQL Server 2014 Developer - duplicate (do not use) SQL Server 2014 Enterprise - duplicate (do not use) SQL Server 2014 Standard - duplicate (do not use)

บทความนี้อธิบายถึงปัญหาที่เกิดขึ้นระหว่างการสอบถามดัชนี clustered columnstore ใน Microsoft SQL Server 2014 บทความนี้ มีวิธีแก้ไขปัญหา นี้

สรุป

เมื่อคุณใช้คิวรีที่สแกนดัชนีที่เก็บคอลัมน์แบบกลุ่มใน Microsoft SQL Server 2014 คุณอาจได้รับผลลัพธ์คิวรีบางส่วนภายใต้เงื่อนไขที่ไม่ค่อยเกิดขึ้น

ปัญหานี้เกิดขึ้นเมื่อมีการเรียกใช้การดําเนินการต่อไปนี้

ขั้นตอนที่ 1

คําสั่ง Transact-SQL [INSERT หรือ BULK-INSERT] จะแทรกข้อมูลลงในตารางที่มีดัชนีที่เก็บคอลัมน์แบบคลัสเตอร์ ระหว่างการดําเนินการนี้ เงื่อนไขต่อไปนี้จะใช้:

  • เมื่อคําสั่ง Transact-SQL ถึงเกณฑ์กลุ่มแถว จะปิดกลุ่มแถว R1 ที่มีเซ็กเมนต์ S1
  • ส่วน S1 ชี้ไปยังพจนานุกรมภายในเครื่อง D1
  • คําสั่งยังคงแทรกแถวลงในกลุ่มแถวใหม่ R2
  • เมื่อปิดกลุ่มแถว R1 พจนานุกรมภายในเครื่อง D1 ก็ไม่จําเป็นต้องปิดด้วย ถ้าพจนานุกรม D1 ยังมีพื้นที่ว่างอยู่ คุณสามารถเปิดไว้และนํามาใช้ใหม่ในกลุ่มแถว R2 ใหม่ได้

ขั้นตอนที่ 2

ถ้าคําสั่ง Transact-SQL สิ้นสุดลงอย่างผิดปกติหรือถูกยกเลิกก่อนที่จะปิดกลุ่มแถว R2 ใหม่ เงื่อนไขต่อไปนี้จะถูกนําไปใช้:

  • การเปลี่ยนแปลงเมตาดาต้าของที่เก็บคอลัมน์จะเกิดขึ้นในทรานแซคชันย่อยที่ดําเนินการโดยไม่ขึ้นกับทรานแซคชันภายนอก
  • ในจุดนี้ กลุ่มแถว R1 จะยังคงอยู่ในตารางระบบในสถานะ "อยู่ระหว่างการก่อสร้าง" หรือมองไม่เห็น และส่วน S1 อ้างอิงพจนานุกรม D1
  • ไม่มีแถวสร้างในตารางระบบสําหรับพจนานุกรม D1 ทั้งนี้เนื่องจากคําสั่ง Transact-SQL ไม่เคยมีโอกาสปิดแถวที่มีอยู่ ดังนั้น แถวที่มีอยู่จะยังคงอยู่

ขั้นตอนที่ 3

ในสถานการณ์ทั่วไป ถ้างานพื้นหลังของ Tuple Mover เริ่มต้นหลังจากคําสั่ง Transact-SQL สิ้นสุดลง งานเบื้องหลังจะลบกลุ่มแถว R1 และส่วน S1 ที่มองไม่เห็นออก ถ้าคําสั่ง Transact-SQL ใหม่เริ่มต้นแล้วและสร้างกลุ่มแถว R3 ที่มีส่วน S3 ใหม่ที่จําเป็นต้องใช้พจนานุกรมภายในเครื่องใหม่ คุณจะไม่สามารถนํา ID ภายในของพจนานุกรม D1 มาใช้ใหม่ได้ This is because the in-memory state of the columnstore keeps track of the dictionary IDs that are used. ดังนั้น ส่วน S3 จะอ้างอิงพจนานุกรมใหม่ D2

หมายเหตุ เงื่อนไขในขั้นตอนนี้เป็นเงื่อนไขทั่วไป ดังนั้นจึงไม่มีการทุจริตเกิดขึ้น

ขั้นตอนที่ 4

ถ้า SQL Server สูญเสียสถานะในหน่วยความจําของพจนานุกรม D1 ก่อนที่งานตัวย้ายทูเปิลจะมีผล (และทํางานตามที่อธิบายไว้ในขั้นตอนที่ 3) ปัญหาที่อธิบายไว้ในบทความนี้จะเกิดขึ้น

บันทึกย่อ

  • เหตุการณ์นี้เกิดขึ้นด้วยเหตุผลต่อไปนี้:

    • SQL Server ประสบปัญหาหน่วยความจํามากเกินไป และเนื้อหาในหน่วยความจําของพจนานุกรม D1 ถูกนําออกจากหน่วยความจํา
    • อินสแตนซ์ของ SQL Server ถูกเริ่มระบบใหม่
    • ฐานข้อมูลที่มีดัชนี clustered columnstore จะออฟไลน์แล้วออนไลน์อีกครั้ง
  • หลังจากเหตุการณ์ใดเหตุการณ์หนึ่งเหล่านี้เกิดขึ้นและ SQL Server โหลดโครงสร้างในหน่วยความจําใหม่ จะไม่มีระเบียนว่ามีพจนานุกรม D1 และ ID ภายในของพจนานุกรม D1 อยู่ ทั้งนี้เนื่องจากพจนานุกรม D1 ไม่ถูกเก็บไว้ในตารางระบบเมื่อคําสั่ง Transact-SQL สิ้นสุดหรือสิ้นสุดลง

  • ถ้างานพื้นหลังตัวเสนอทูเปิลเริ่มต้นที่จุดนี้ จะไม่มีข้อผิดพลาดเกิดขึ้นเนื่องจากเงื่อนไขที่อธิบายไว้ในขั้นตอนที่ 3 จะถูกนําไปใช้

  • ถ้ากลุ่มแถว R3 ใหม่ถูกสร้างขึ้นก่อนที่งานพื้นหลังของ Tuple Mover จะเริ่มต้น (ต่อรายการสัญลักษณ์แสดงหัวข้อย่อยก่อนหน้านี้) SQL Server จะกําหนด ID ภายในเดียวกันไปยังพจนานุกรม D1 ใหม่ และอ้างอิงพจนานุกรม D1 สําหรับส่วน S3 ในกลุ่มแถว R3

  • เมื่องานพื้นหลังตัวย้ายทูเปิลเริ่มขึ้นหลังจากการดําเนินการก่อนหน้า จะทิ้งกลุ่มแถว R1 ที่มองไม่เห็นและส่วน S1 พร้อมกับพจนานุกรมใหม่ D1 ซึ่งเกิดขึ้นเนื่องจาก Tuple Mover พิจารณาว่าพจนานุกรมใหม่ D1 และพจนานุกรมต้นฉบับ D1 ที่อ้างอิง S1 เหมือนกัน

    หมายเหตุ เมื่อเกิดปัญหานี้ คุณจะไม่สามารถสอบถามเนื้อหาของกลุ่มแถว R3 ได้

การแก้ปัญหา

ปัญหานี้ได้รับการแก้ไขครั้งแรกในการอัปเดตแบบสะสมต่อไปนี้สําหรับ SQL Server:

การอัปเดตสะสม 1 สําหรับ SQL Server 2014 SP1
        
         การอัปเดตสะสม 8 สําหรับ SQL Server 2014
การแก้ไขปัญหานี้รวมอยู่ในการอัปเดตรุ่นการแจกจ่ายทั่วไป (GDR) ต่อไปนี้ด้วย:

การอัปเดตความปลอดภัยสําหรับ SQL Server 2014 QFE  
การอัปเดตนี้รวมถึงการอัปเดตสะสม 8 การแก้ไขที่สําคัญนี้ และการอัปเดตความปลอดภัย MS15-058 ที่จําเป็น

แพคเกจโปรแกรมปรับปรุงความปลอดภัยสําหรับ SQL Server 2014 GDR  
การอัปเดตนี้รวมถึงการแก้ไขที่สําคัญและการแก้ไขความปลอดภัยแบบสะสมผ่าน MS15-058

การอัปเดตที่ไม่ใช่ด้านความปลอดภัยสําหรับ SQL Server 2014 Service Pack 1 GDR  
การอัปเดตนี้มีเฉพาะการแก้ไขที่สําคัญนี้เท่านั้น

เกี่ยวกับการอัปเดตสะสมสําหรับ SQL Server

การอัปเดตแบบสะสมใหม่แต่ละรายการสําหรับ SQL Server จะมีโปรแกรมแก้ไขด่วนและการแก้ไขข้อบกพร่องด้านความปลอดภัยทั้งหมดที่รวมอยู่ในการอัปเดตแบบสะสมครั้งก่อนหน้า ดูการอัปเดตสะสมล่าสุดสําหรับ SQL Server:

      

ข้อมูลเพิ่มเติม

ข้อความแสดงข้อผิดพลาดในฐานข้อมูลที่ได้รับผลกระทบในปัจจุบัน ถ้าคุณเรียกใช้ DBCC CHECKDB หลังจากที่คุณนําการแก้ไขนี้ไปใช้ คุณจะได้รับข้อความแสดงข้อผิดพลาดต่อไปนี้:

หมายเหตุ

ข้อความ 5289, ระดับ 16, สถานะ 1, บรรทัด 1
ดัชนีที่เก็บคอลัมน์แบบกลุ่ม 'cci' บนตาราง 't' มีค่าข้อมูลอย่างน้อยหนึ่งค่าที่ไม่ตรงกับค่าข้อมูลในพจนานุกรม คืนค่าข้อมูลจากการสํารองข้อมูล

ในฐานข้อมูลที่ได้รับผลกระทบในปัจจุบัน เมื่อคุณเรียกใช้คิวรีที่สแกนตารางที่ได้รับผลกระทบหลังจากที่คุณนําการแก้ไขนี้ไปใช้ คุณได้รับข้อความแสดงข้อผิดพลาดต่อไปนี้:

หมายเหตุ

ข้อความ 5288, ระดับ 16, สถานะ 1, บรรทัด 1
ดัชนี Columnstore มีค่าข้อมูลอย่างน้อยหนึ่งค่าที่ไม่ตรงกับค่าข้อมูลในพจนานุกรม โปรดเรียกใช้ DBCC CHECKDB สําหรับข้อมูลเพิ่มเติม

ถ้าคุณได้รับข้อผิดพลาดเหล่านี้ คุณสามารถบันทึกข้อมูลที่ไม่เสียหายได้โดยการส่งออกข้อมูลของคอลัมน์/กลุ่มแถวที่ไม่ได้รับผลกระทบเป็นกลุ่ม แล้วโหลดข้อมูลใหม่หลังจากที่คุณวางหรือสร้างดัชนี clustered Columnstore คุณควรเปิดใช้งานการติดตามค่าสถานะ 10207 เพื่อระงับข้อผิดพลาด 5288 และย้อนกลับไปเป็นลักษณะการทํางานแบบเดิมของการข้ามกลุ่มแถวที่เสียหาย

หมายเหตุ ข้อความแสดงข้อผิดพลาด 5288 และ 5289 ถูกสร้างขึ้นสําหรับกลุ่มแถว R3 ที่มีเซกเมนต์ S3 ติดตามสถานะ 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 ชุดผลลัพธ์ที่ว่างเปล่าจะระบุว่า ฐานข้อมูลไม่ได้รับผลกระทบ

  • ดําเนินการคิวรีนี้ระหว่างช่วงเวลาที่ไม่มีกิจกรรมที่จะสร้างกลุ่มแถวใหม่หรือเปลี่ยนแปลงสถานะของกลุ่มแถวที่มีอยู่ ตัวอย่างเช่น กิจกรรมต่อไปนี้สามารถปรับเปลี่ยนสถานะของกลุ่มแถว: การสร้างดัชนี จัดระเบียบดัชนีใหม่ แทรกเป็นกลุ่ม Tuple Mover การบีบอัดที่เก็บส่วนต่าง

    ก่อนที่คุณจะดําเนินการคิวรี คุณสามารถปิดใช้งานงานเครื่องมือย้ายทูเปิลพื้นหลังได้โดยใช้แฟล็กการติดตาม 634 ใช้คําสั่งนี้เพื่อปิดใช้งานงานเบื้องหลัง: DBCC TRACEON ( 634 , -1 ) หลังจากคิวรีเสร็จสิ้นการดําเนินการ อย่าลืมเปิดใช้งานงานพื้นหลังอีกครั้งโดยใช้คําสั่ง: DBCC TRACEOFF ( 634 , -1 )

    นอกจากนี้ ให้ตรวจสอบให้แน่ใจว่าไม่มีคําสั่ง BULK INSERT/BCP/SELECT-INTO ที่แทรกข้อมูลลงในตารางที่ใช้ดัชนีที่เก็บคอลัมน์ขณะที่คิวรีนี้กําลังทํางานอยู่

    เราขอแนะนําให้ใช้ขั้นตอนเหล่านี้เพื่อป้องกันไม่ให้คิวรีส่งกลับผลลัพธ์ที่ผิด

สถานะ

Microsoft ได้ยืนยันว่านี่เป็นปัญหาที่เกิดขึ้นกับผลิตภัณฑ์ของ Microsoft ที่แสดงไว้ในส่วน "นำไปใช้กับ"