LOB_DATA สแกนตารางช้าและคำถาม I / O บางข้อ


19

ฉันมีตารางที่ค่อนข้างใหญ่โดยหนึ่งในคอลัมน์เป็นข้อมูล XML และขนาดเฉลี่ยของรายการ XML อยู่ที่ประมาณ 15 กิโลไบต์ คอลัมน์อื่น ๆ ทั้งหมดเป็น ints ปกติ bigints GUIDs ฯลฯ หากต้องการมีตัวเลขที่เป็นรูปธรรมสมมติว่าตารางมีหนึ่งล้านแถวและมีขนาดประมาณ 15 GB

สิ่งที่ฉันสังเกตคือตารางนี้ช้ามากในการเลือกข้อมูลจากถ้าฉันต้องการเลือกคอลัมน์ทั้งหมด เมื่อฉันทำ

SELECT TOP 1000 * FROM TABLE

ใช้เวลาประมาณ 20-25 วินาทีในการอ่านข้อมูลจากดิสก์ - แม้ว่าฉันจะไม่ได้กำหนดผลลัพธ์ไว้ก็ตาม ฉันเรียกใช้แบบสอบถามด้วยแคชเย็น (เช่นหลังจากDBCC DROPCLEANBUFFERS) นี่คือผลสถิติ IO:

จำนวนการสแกน 1, อ่านโลจิคัล 364, อ่านฟิสิคัล 24 อ่านล่วงหน้าอ่าน 7191, ล็อบโลจิคัลอ่าน 7924, lob ฟิสิคัลอ่าน 1690, lob อ่านล่วงหน้าอ่าน 3968

มันคว้าข้อมูลประมาณ 15 MB แผนการดำเนินการแสดงการสแกนดัชนีแบบกลุ่มตามที่ฉันต้องการ

ไม่มี IO เกิดขึ้นบนดิสก์นอกจากแบบสอบถามของฉัน ฉันได้ตรวจสอบแล้วว่าการแตกแฟรกเมนต์ดัชนีคลัสเตอร์ใกล้เคียงกับ 0% นี่คือไดรฟ์ SATA ระดับผู้บริโภค แต่ฉันยังคิดว่า SQL Server จะสามารถสแกนตารางได้เร็วกว่า ~ 100-150 MB / นาที

การแสดงตนของฟิลด์ XML ทำให้ข้อมูลตารางส่วนใหญ่อยู่ในหน้า LOB_DATA (อันที่จริงแล้วประมาณ 90% ของหน้าตารางเป็น LOB_DATA)

ฉันเดาคำถามของฉัน - ฉันคิดถูกว่าหน้า LOB_DATA สามารถทำให้การสแกนช้าไม่เพียงเพราะขนาดของพวกเขา แต่เนื่องจาก SQL Server ไม่สามารถสแกนดัชนีคลัสเตอร์ได้อย่างมีประสิทธิภาพเมื่อมีหน้า LOB_DATA จำนวนมากในตาราง?

ยิ่งกว้างขึ้น - ถือว่ามีเหตุผลหรือไม่ที่จะมีโครงสร้างตาราง / รูปแบบข้อมูล คำแนะนำสำหรับการใช้ Filestream มักจะระบุขนาดของฟิลด์ที่ใหญ่กว่ามากดังนั้นฉันจึงไม่อยากไปเส้นทางนั้น ฉันไม่พบข้อมูลที่ดีเกี่ยวกับสถานการณ์นี้

ฉันคิดเกี่ยวกับการบีบอัด XML แต่ต้องทำกับไคลเอนต์หรือกับ SQLCLR และต้องการงานที่จะใช้ในระบบ

ฉันลองใช้การบีบอัดและเนื่องจาก XML มีความซ้ำซ้อนสูงฉันจึงสามารถบีบอัด XML จาก 20KB ถึง ~ 2.5KB และเก็บไว้ในคอลัมน์ VARBINARY เพื่อป้องกันการใช้หน้าข้อมูล LOB ความเร็วนี้เลือก 20 เท่าในการทดสอบของฉัน


อเล็กซ์: ไม่แน่ใจว่าคุณเห็นการสนทนาที่เกี่ยวข้องกับคำตอบของฉัน (ลิงก์อยู่ในความคิดเห็นด้านล่างคำตอบของฉัน) แต่ฉันสามารถเข้าใกล้การทำซ้ำสถานการณ์ของคุณ ฉันเติมข้อมูลตารางที่ตรงกัน (เท่าที่ฉันมีข้อมูล) คำอธิบายของคุณและได้รับสถิติ I / O ที่คล้ายกันมาก ยกเว้น "การอ่านทางกายภาพ LOB" ไม่เคยแม้แต่จะปิด ดังนั้นฉันจึงสงสัยว่าถ้าคุณอัปเดต XML (แต่ไม่ใช่คอลัมน์อื่น) และ / หรือมีการกระจายตัวของไฟล์ข้อมูลของคุณจำนวนมาก ฉันยังไม่รังเกียจที่จะรับ DDL ของตารางและการตั้งค่าการเติบโตอัตโนมัติของคุณสำหรับไฟล์ข้อมูลแต่ละไฟล์และคุณลดขนาดไฟล์ข้อมูลของคุณหรือไม่?
โซโลมอน Rutzky

ก่อนอื่น - ขอบคุณมากสำหรับคำตอบอย่างละเอียดฉันไม่สามารถมีส่วนร่วมในการอภิปรายในเวลานี้เนื่องจากไม่มีเวลา ตอนนี้คุณพูดถึงสิ่งนี้ (ฉันไม่คิดว่าเมื่อถามคำถาม) - ฟิลด์ XML ถูกอัปเดตหลายครั้งหลังจากที่สร้างขึ้นและสร้างขึ้นเล็กน้อย ดังนั้นฉันสงสัยว่าตอนแรกมันถูกเก็บไว้ในแถวและหลังจากการปรับปรุงบางอย่างมันจะถูกย้ายออกไปสู่โครงสร้างหน้า LOB และจากนั้นจะได้รับการปรับปรุงเพิ่มเติม
Alexander Shelemin

(ต่อ) ฉันตรวจสอบการกระจายตัวของไฟล์ก่อนถามคำถามและเครื่องมือ Windows ในตัวคิดว่ามันโอเคดังนั้นฉันจึงไม่ได้ดูเพิ่มเติมอีก การเติบโตอัตโนมัติเป็นค่าเริ่มต้นโดย 1 MB ฉันเชื่อและไฟล์ข้อมูลไม่ได้ลดขนาดลง
Alexander Shelemin

เลือก 1,000 อันดับแรก * มีความสำคัญในกรณีของฉันโดยเฉพาะ ฉันเข้าใจอย่างแน่นอนว่ามันถือว่าเป็นการปฏิบัติที่ไม่ดี แต่การตัดสินใจออกแบบแอพพลิเคชั่นบางอย่างยากที่จะเปลี่ยนแปลงได้หลังจากที่พวกเขาใช้งานมาเป็นเวลานาน Select * นั้นใช้เป็นกลยุทธ์การจำลองข้อมูลข้ามฐานข้อมูลระหว่างส่วนประกอบต่าง ๆ ในแอพของเรา มีข้อดีอยู่ตัวอย่างเช่นเราสามารถทำการจัดการโดยพลการกับ data / schema ได้ทันทีซึ่งจะยากกับเทคนิคการจำลองแบบในตัว แต่มันมาพร้อมกับปัญหา
Alexander Shelemin

อเล็กซ์SELECT *ไม่ใช่ปัญหาหากคุณต้องการข้อมูล XML เป็นเพียงปัญหาถ้าคุณไม่ต้องการข้อมูล XML ในกรณีนี้เหตุใดจึงทำให้แบบสอบถามช้าลงเพื่อให้ได้ข้อมูลที่คุณไม่ได้ใช้ ฉันถามเกี่ยวกับการอัปเดตของ XML ที่สงสัยว่าการแยกส่วนในหน้า LOB ไม่ได้รับการรายงานอย่างถูกต้องหรือไม่ อะไรคือสาเหตุที่ฉันถามคำตอบของฉันคุณทราบได้อย่างไรว่าดัชนีคลัสเตอร์ไม่กระจัดกระจาย คุณสามารถให้คำสั่งที่คุณวิ่งได้หรือไม่? และคุณได้ทำการสร้าง REBUILD เต็มรูปแบบในดัชนีแบบกลุ่มหรือไม่ (ต่อ)
โซโลมอน Rutzky

คำตอบ:


11

การแสดงตนของฟิลด์ XML ทำให้ข้อมูลตารางส่วนใหญ่อยู่ในหน้า LOB_DATA (อันที่จริงแล้วประมาณ 90% ของหน้าตารางเป็น LOB_DATA)

เพียงแค่มีคอลัมน์ XML ในตารางนั้นจะไม่มีผลกระทบนั้น การมีอยู่ของข้อมูล XML ที่ทำให้บางส่วนของข้อมูลแถวถูกจัดเก็บนอกแถวบนหน้า LOB_DATA ภายใต้เงื่อนไขบางประการ และในขณะที่หนึ่ง (หรืออาจเป็นหลาย ๆ ;-) อาจโต้เถียงว่า duh XMLคอลัมน์นั้นหมายความว่าจะมีข้อมูล XML แน่นอนไม่รับประกันว่าข้อมูล XML จะต้องถูกเก็บไว้นอกแถว: เว้นแต่แถวจะเต็มไปแล้วสวยมากแล้ว นอกเหนือจากการเป็นข้อมูล XML เอกสารขนาดเล็ก (มากถึง 8000 ไบต์) อาจพอดีกับแถวและไม่เคยไปที่หน้า LOB_DATA

ฉันถูกต้องหรือไม่ที่คิดว่าหน้า LOB_DATA สามารถทำให้การสแกนช้าไม่เพียงเพราะขนาดของมัน แต่เพราะ SQL Server ไม่สามารถสแกนดัชนีคลัสเตอร์ได้อย่างมีประสิทธิภาพเมื่อมีหน้า LOB_DATA จำนวนมากในตาราง

การสแกนหมายถึงการดูทุกแถว แน่นอนเมื่ออ่านหน้าข้อมูลข้อมูลในแถวทั้งหมดจะถูกอ่านแม้ว่าคุณจะเลือกชุดย่อยของคอลัมน์ก็ตาม ความแตกต่างกับข้อมูล LOB คือถ้าคุณไม่เลือกคอลัมน์นั้นข้อมูลนอกแถวจะไม่ถูกอ่าน ดังนั้นจึงไม่ยุติธรรมเลยที่จะสรุปว่า SQL Server สามารถสแกนดัชนีกลุ่มนี้ได้อย่างมีประสิทธิภาพเนื่องจากคุณไม่ได้ทดสอบอย่างแน่นอน (หรือคุณทดสอบครึ่งหนึ่งแล้ว) คุณเลือกคอลัมน์ทั้งหมดซึ่งรวมถึงคอลัมน์ XML และตามที่คุณกล่าวถึงซึ่งเป็นที่ตั้งของข้อมูลส่วนใหญ่

ดังนั้นเราจึงรู้แล้วว่าการSELECT TOP 1000 *ทดสอบไม่เพียง แต่อ่านหน้าข้อมูลขนาด 8k ทั้งหมดในแถวเดียว แต่กลับไปที่สถานที่อื่นต่อแต่ละแถวแทน โครงสร้างที่แน่นอนของข้อมูล LOB นั้นอาจแตกต่างกันไปตามขนาดของข้อมูล จากการวิจัยแสดงให้เห็นที่นี่ ( ขนาดของ LOB Pointer สำหรับ (MAX) ประเภทคือ Varchar, Varbinary, Etc? ) มีการจัดสรร LOB สองแบบดังนี้:

  1. Inline Root - สำหรับข้อมูลระหว่าง 8001 ถึง 40,000 (จริง ๆ 42,000) ไบต์การอนุญาตให้ใช้พื้นที่จะมี 1 ถึง 5 ตัวชี้ (24 - 72 ไบต์) ในแถวที่ชี้ไปยังหน้า LOB โดยตรง
  2. TEXT_TREE - สำหรับข้อมูลที่มีมากกว่า 42,000 ไบต์หรือหากตัวชี้ 1 ถึง 5 ไม่พอดีในแถวจากนั้นจะมีเพียง 24 ไบต์ตัวชี้ไปยังหน้าเริ่มต้นของรายการตัวชี้ไปยังหน้า LOB (เช่น " หน้า text_tree ")

หนึ่งในสองสถานการณ์นี้เกิดขึ้นในแต่ละครั้งที่คุณดึงข้อมูล LOB ที่มีมากกว่า 8000 ไบต์หรือไม่พอดีในแถว ฉันโพสต์สคริปต์ทดสอบบน PasteBin.com (สคริปต์T-SQL เพื่อทดสอบการจัดสรร LOB และการอ่าน ) ที่แสดงการจัดสรร LOB 3 ประเภท (ขึ้นอยู่กับขนาดของข้อมูล) รวมถึงผลกระทบที่แต่ละรายการมีต่อตรรกะและ อ่านทางกายภาพ ในกรณีของคุณถ้าข้อมูล XML น้อยกว่า 42,000 ไบต์ต่อแถวจริงๆแล้วไม่มีข้อมูลใด ๆ (หรือน้อยมาก) ในโครงสร้าง TEXT_TREE ที่มีประสิทธิภาพน้อยที่สุด

หากคุณต้องการทดสอบความเร็วของ SQL Server ที่สามารถสแกนดัชนีแบบคลัสเตอร์ให้ทำSELECT TOP 1000แต่ระบุคอลัมน์อย่างน้อยหนึ่งคอลัมน์โดยไม่รวมคอลัมน์ XML นั้น สิ่งนั้นมีผลต่อผลลัพธ์ของคุณอย่างไร ควรจะเร็วกว่านี้สักหน่อย

มันถือว่าสมเหตุสมผลที่จะมีโครงสร้างตาราง / รูปแบบข้อมูลหรือไม่

เนื่องจากเรามีคำอธิบายที่ไม่สมบูรณ์เกี่ยวกับโครงสร้างตารางจริงและรูปแบบข้อมูลคำตอบใด ๆ อาจไม่ดีที่สุดขึ้นอยู่กับรายละเอียดที่ขาดหายไปเหล่านั้น โดยที่ในใจฉันจะบอกว่าไม่มีอะไรที่ชัดเจนเกี่ยวกับโครงสร้างตารางหรือรูปแบบข้อมูลของคุณ

ฉันสามารถบีบอัด XML จาก 20KB เป็น ~ 2.5KB และเก็บไว้ในคอลัมน์ VARBINARY เพื่อป้องกันการใช้หน้าข้อมูล LOB ความเร็วนี้เลือก 20 เท่าในการทดสอบของฉัน

นั่นทำให้การเลือกคอลัมน์ทั้งหมดหรือแม้แต่ข้อมูล XML (ตอนนี้เข้าVARBINARY) เร็วขึ้น แต่มันเจ็บจริงแบบสอบถามที่ไม่เลือกข้อมูล "XML" สมมติว่าคุณมีประมาณ 50 ไบต์ในคอลัมน์อื่นและมีขนาดFILLFACTORเท่ากับ 100 จากนั้น:

  • ไม่มีการบีบอัดXMLข้อมูล15k ของข้อมูลควรใช้ 2 LOB_DATA หน้าซึ่งต้องใช้ 2 พอยน์เตอร์สำหรับ Inline Root ตัวชี้แรกคือ 24 ไบต์และที่สองคือ 12 สำหรับทั้งหมด 36 ไบต์เก็บไว้ในแถวสำหรับข้อมูล XML ขนาดแถวทั้งหมดคือ 86 ไบต์และคุณสามารถใส่ได้ประมาณ 93 แถวในหน้าข้อมูล 8060 ไบต์ ดังนั้นแถว 1 ล้านแถวต้องใช้หน้าข้อมูล 10,753 หน้า

  • การบีบอัดที่กำหนดเอง: VARBINARYข้อมูล2.5k จะพอดีกับแถว ขนาดแถวทั้งหมดคือ 2610 (2.5 * 1024 = 2560) ไบต์และคุณสามารถใส่ได้เพียง 3 แถวในหน้าข้อมูล 8060 ไบต์ ดังนั้นแถว 1 ล้านแถวต้องการหน้าข้อมูล 333,334 หน้า

ดังนั้นการใช้การบีบอัดแบบกำหนดเองจะทำให้หน้าข้อมูลเพิ่มขึ้น 30x สำหรับดัชนีแบบคลัสเตอร์ ความหมายแบบสอบถามทั้งหมดที่ใช้การสแกนดัชนีแบบคลัสเตอร์จะมีหน้าข้อมูลเพิ่มเติมอีกประมาณ 322,500 หน้า โปรดดูหัวข้อโดยละเอียดด้านล่างเพื่อรับข้อมูลเพิ่มเติมเกี่ยวกับการบีบอัดประเภทนี้

ฉันจะระมัดระวังกับการทำ refactoring ใด ๆ SELECT TOP 1000 *ขึ้นอยู่กับประสิทธิภาพการทำงานของ ซึ่งไม่น่าจะเป็นข้อความค้นหาที่แอปพลิเคชันจะออกและไม่ควรใช้เป็นพื้นฐานสำหรับการปรับให้เหมาะสมที่ไม่มีความจำเป็น

สำหรับข้อมูลโดยละเอียดเพิ่มเติมและการทดสอบเพิ่มเติมโปรดลองดูในส่วนด้านล่าง


คำถามนี้ไม่สามารถให้คำตอบที่ชัดเจนได้ แต่อย่างน้อยเราสามารถสร้างความคืบหน้าและแนะนำการวิจัยเพิ่มเติมเพื่อช่วยให้เราเข้าใกล้การค้นหาประเด็นที่แน่นอน (ตามหลักฐานที่ดี)

สิ่งที่เรารู้:

  1. ตารางมีประมาณ 1 ล้านแถว
  2. ขนาดโต๊ะประมาณ 15 GB
  3. ตารางที่มีหนึ่งXMLคอลัมน์และอีกหลายคอลัมน์อื่น ๆ ประเภท: INT, BIGINT, UNIQUEIDENTIFIER"ฯลฯ"
  4. XMLคอลัมน์ "ขนาด" คือโดยเฉลี่ยประมาณ 15k
  5. หลังจากทำงานDBCC DROPCLEANBUFFERSแล้วจะใช้เวลา 20-25 วินาทีในการค้นหาให้เสร็จสมบูรณ์:SELECT TOP 1000 * FROM TABLE
  6. กำลังสแกนดัชนีแบบคลัสเตอร์
  7. การแตกแฟรกเมนต์ในดัชนีแบบคลัสเตอร์ใกล้เคียงกับ 0%

สิ่งที่เราคิดว่าเรารู้:

  1. ไม่มีกิจกรรมดิสก์อื่นนอกเหนือจากการค้นหาเหล่านี้ คุณแน่ใจไหม? แม้ว่าจะไม่มีการสอบถามผู้ใช้อื่น ๆ จะมีการดำเนินการพื้นหลังที่เกิดขึ้น? มีกระบวนการภายนอกไปยัง SQL Server ที่ทำงานบนเครื่องเดียวกันที่อาจใช้ IO บางอย่างหรือไม่ อาจไม่มี แต่ก็ไม่ชัดเจนตามข้อมูลที่ให้ไว้เท่านั้น
  2. กำลังส่งคืนข้อมูล XML 15 MB ตัวเลขนี้ขึ้นอยู่กับอะไร การประเมินมาจาก 1,000 แถวคูณกับค่าเฉลี่ยของข้อมูล XML 15k ต่อแถว? หรือการรวมแบบเป็นโปรแกรมของสิ่งที่ได้รับสำหรับการค้นหานั้น? หากเป็นเพียงการประมาณค่าฉันจะไม่เชื่อถือเนื่องจากการเผยแพร่ข้อมูล XML อาจไม่ได้เป็นไปในลักษณะที่ค่าเฉลี่ยโดยนัยง่าย ๆ
  3. การบีบอัด XML อาจช่วยได้ คุณจะทำการบีบอัดใน. NET อย่างไร? ผ่านคลาส GZipStreamหรือDeflateStreamหรือไม่ นี่ไม่ใช่ตัวเลือกที่ไม่มีค่าใช้จ่าย แน่นอนว่ามันจะบีบอัดข้อมูลบางส่วนด้วยเปอร์เซ็นต์ที่มาก แต่ก็ต้องใช้ CPU มากขึ้นเนื่องจากคุณจะต้องมีกระบวนการเพิ่มเติมในการบีบอัด / คลายข้อมูลในแต่ละครั้ง แผนนี้จะลบความสามารถของคุณไปที่:

    • แบบสอบถามข้อมูล XML ผ่านทาง.nodes, .value, .queryและ.modifyฟังก์ชั่น XML
    • จัดทำดัชนีข้อมูล XML

      โปรดทราบ (เนื่องจากคุณระบุว่า XML เป็น "ซ้ำซ้อนสูง") ซึ่งXMLประเภทข้อมูลนั้นได้รับการปรับให้เหมาะสมแล้วโดยที่มันเก็บองค์ประกอบและชื่อแอตทริบิวต์ในพจนานุกรมกำหนด ID ดัชนีจำนวนเต็มให้กับแต่ละรายการจากนั้นใช้ ID จำนวนเต็มนั้น ตลอดทั้งเอกสาร (ดังนั้นจึงไม่ซ้ำชื่อเต็มต่อการใช้งานแต่ละครั้งและไม่ซ้ำอีกครั้งเป็นแท็กปิดสำหรับองค์ประกอบ) ข้อมูลจริงยังมีการลบพื้นที่สีขาวที่ไม่เกี่ยวข้อง นี่คือเหตุผลที่เอกสาร XML ที่แยกออกมาไม่ได้เก็บโครงสร้างดั้งเดิมไว้และทำไมองค์ประกอบที่ว่างเปล่าจึงแยกออกมา<element />แม้ว่าจะเป็นเช่นนั้นก็ตาม<element></element>. ดังนั้นกำไรจากการบีบอัดผ่าน GZip (หรือสิ่งอื่นใด) จะถูกค้นพบโดยการบีบอัดองค์ประกอบและ / หรือค่าคุณลักษณะซึ่งเป็นพื้นที่ผิวที่เล็กกว่ามากซึ่งสามารถปรับปรุงได้กว่าที่คาดไว้ส่วนใหญ่และไม่น่าจะสูญเสีย ความสามารถตามที่ระบุไว้ข้างต้นโดยตรง

      โปรดทราบว่าการบีบอัดข้อมูล XML และการจัดเก็บVARBINARY(MAX)ผลลัพธ์จะไม่กำจัดการเข้าถึง LOB แต่จะลดลง ขึ้นอยู่กับขนาดของข้อมูลที่เหลือในแถวค่าที่บีบอัดอาจพอดีในแถวหรืออาจยังต้องการหน้า LOB

ข้อมูลนั้นมีประโยชน์ไม่เพียงพอ มีปัจจัยหลายอย่างที่มีผลต่อประสิทธิภาพการค้นหาดังนั้นเราจึงต้องการภาพที่มีรายละเอียดมากขึ้นว่าเกิดอะไรขึ้น

สิ่งที่เราไม่รู้ แต่ต้อง:

  1. ทำไมประสิทธิภาพของSELECT *สสาร นี่เป็นรูปแบบที่คุณใช้ในรหัส ถ้าเป็นเช่นนั้นทำไม
  2. ประสิทธิภาพในการเลือกเฉพาะคอลัมน์ XML คืออะไร อะไรคือสถิติและระยะเวลาถ้าคุณทำเพียงแค่: SELECT TOP 1000 XmlColumn FROM TABLE;?
  3. ใช้เวลาประมาณ 20-25 วินาทีในการส่งคืน 1,000 แถวเหล่านี้เกี่ยวข้องกับปัจจัยเครือข่าย (การรับข้อมูลผ่านการโยง) และจำนวนเท่าใดที่เกี่ยวข้องกับปัจจัยลูกค้า (การแสดงผลที่ประมาณ 15 MB บวกกับส่วนที่เหลือของ ข้อมูล XML ในตารางใน SSMS หรืออาจบันทึกลงดิสก์)

    การแยกตัวประกอบทั้งสองด้านออกจากการดำเนินการบางครั้งสามารถทำได้โดยไม่ส่งคืนข้อมูล ตอนนี้ใคร ๆ ก็คิดว่าจะเลือกเป็น Temporary Table หรือ Table Variable แต่นี่จะแนะนำตัวแปรใหม่บางอย่าง (เช่น disk I / O สำหรับtempdbการเขียน Transaction Log, การเติบโตอัตโนมัติของ tempdb data และ / หรือ log file ที่ต้องการ พื้นที่ในบัฟเฟอร์พูล ฯลฯ ) ปัจจัยใหม่ทั้งหมดเหล่านี้สามารถเพิ่มเวลาการสืบค้นได้จริง แต่โดยปกติฉันจะเก็บคอลัมน์ไว้ในตัวแปร (ของประเภทข้อมูลที่เหมาะสมไม่ใช่SQL_VARIANT) ที่จะถูกเขียนทับด้วยแถวใหม่แต่ละแถว (เช่นSELECT @Column1 = tab.Column1,...)

    อย่างไรก็ตามเป็นที่แหลมออกโดย @PaulWhite นี้ DBA.StackExchange Q & A, ตรรกะอ่านที่แตกต่างกันเมื่อมีการเข้าถึงข้อมูลลอบเดียวกันมีการวิจัยเพิ่มเติมของตัวเองโพสต์บน Pastebin ( สคริปต์ T-SQL เพื่อทดสอบสถานการณ์ต่าง ๆ สำหรับการลอบอ่าน ) , LOBs จะไม่เข้าถึงได้อย่างต่อเนื่องระหว่างSELECT, SELECT INTO, SELECT @XmlVariable = XmlColumn, และSELECT @XmlVariable = XmlColumn.query(N'/') SELECT @NVarCharVariable = CONVERT(NVARCHAR(MAX), XmlColumn)ดังนั้นทางเลือกของเรามี จำกัด น้อยกว่าที่นี่ แต่นี่คือสิ่งที่สามารถทำได้:

    1. ออกกฎปัญหาเครือข่ายโดยการดำเนินการค้นหาบนเซิร์ฟเวอร์ที่รัน SQL Server ทั้งใน SSMS หรือ SQLCMD.EXE
    2. แยกแยะปัญหาไคลเอนต์ใน SSMS โดยไปที่ตัวเลือกการสืบค้น -> ผลลัพธ์ -> กริดและตรวจสอบตัวเลือกสำหรับ "ทิ้งผลลัพธ์หลังการดำเนินการ" โปรดทราบว่าตัวเลือกนี้จะป้องกันการแสดงผลทั้งหมดรวมถึงข้อความ แต่ยังคงมีประโยชน์ในการแยกแยะเวลาที่ใช้ SSMS ในการจัดสรรหน่วยความจำต่อแต่ละแถวแล้ววาดมันในตาราง
      หรือคุณสามารถดำเนินการค้นหาผ่านทาง sqlcmd.exe -o NUL:โดยตรงและการส่งออกที่จะไปที่ไหนเลยผ่าน:
  4. มีประเภทรอเกี่ยวข้องกับแบบสอบถามนี้หรือไม่ ถ้าใช่ประเภทรอคืออะไร?
  5. คืออะไรที่เกิดขึ้นจริงขนาดของข้อมูลสำหรับXMLคอลัมน์ถูกส่งกลับ ? ขนาดเฉลี่ยของคอลัมน์นั้นตลอดทั้งตารางนั้นไม่สำคัญหากแถว "TOP 1000" มีสัดส่วนของXMLข้อมูลทั้งหมดเป็นสัดส่วนมาก หากคุณต้องการทราบเกี่ยวกับแถวบน 1,000 แถวให้ดูแถวเหล่านั้น กรุณาเรียกใช้ต่อไปนี้:

    SELECT TOP 1000 tab.*,
           SUM(DATALENGTH(tab.XmlColumn)) / 1024.0 AS [TotalXmlKBytes],
           AVG(DATALENGTH(tab.XmlColumn)) / 1024.0 AS [AverageXmlKBytes]
           STDEV(DATALENGTH(tab.XmlColumn)) / 1024.0 AS [StandardDeviationForXmlKBytes]
    FROM   SchemaName.TableName tab;
  6. แน่นอน schema ของตาราง โปรดระบุคำสั่งแบบเต็ม CREATE TABLEรวมถึงดัชนีทั้งหมด
  7. แผนค้นหาหรือไม่ นั่นเป็นสิ่งที่คุณสามารถโพสต์ได้หรือไม่ ข้อมูลนั้นอาจจะไม่เปลี่ยนแปลงอะไรเลย แต่จะดีกว่าที่จะรู้ว่ามันจะไม่ดีไปกว่าการเดาว่ามันจะไม่ผิดและ ;-)
  8. มีการแตกแฟรกเมนต์ทางกายภาพ / ภายนอกในไฟล์ข้อมูลหรือไม่? ในขณะที่สิ่งนี้อาจไม่ใช่ปัจจัยใหญ่ที่นี่เนื่องจากคุณใช้ "SATA ระดับผู้บริโภค" และไม่ใช่ SSD หรือแม้แต่ Super-Expensive SATA ผลของภาคที่สั่งซื้อมาอย่างเหมาะสมจะสังเกตเห็นได้ชัดเจนขึ้นโดยเฉพาะอย่างยิ่งจำนวนภาคเหล่านั้น ที่ต้องอ่านเพิ่มขึ้น
  9. อะไรคือผลลัพธ์ที่แน่นอนของแบบสอบถามต่อไปนี้:

    SELECT * FROM sys.dm_db_index_physical_stats(DB_ID(),
                              OBJECT_ID(N'dbo.SchemaName.TableName'), 1, 0, N'LIMITED');

UPDATE

เกิดขึ้นกับฉันว่าฉันควรพยายามทำซ้ำสถานการณ์นี้เพื่อดูว่าฉันมีพฤติกรรมที่คล้ายคลึงกันหรือไม่ ดังนั้นฉันจึงสร้างตารางที่มีหลายคอลัมน์ (คล้ายกับคำอธิบายที่คลุมเครือในคำถาม) จากนั้นเติมข้อมูลด้วย 1 ล้านแถวและคอลัมน์ XML มีข้อมูลประมาณ 15k ต่อแถว (ดูรหัสด้านล่าง)

สิ่งที่ฉันพบคือการทำSELECT TOP 1000 * FROM TABLEเสร็จใน 8 วินาทีในครั้งแรกและ 2 - 4 วินาทีในแต่ละครั้งหลังจากนั้น (ใช่ดำเนินการDBCC DROPCLEANBUFFERSก่อนเรียกใช้SELECT *แบบสอบถามแต่ละครั้ง) และแล็ปท็อปอายุหลายปีของฉันไม่เร็ว: SQL Server 2012 SP2 Developer Edition, 64 บิต, 6 GB RAM, 2.5 2.5 Ghz Core i5 คู่และไดรฟ์ SATA 5400 RPM ฉันกำลังใช้ SSMS 2014, SQL Server Express 2014, Chrome และอีกหลายอย่าง

ขึ้นอยู่กับเวลาตอบสนองของระบบของฉันฉันจะทำซ้ำว่าเราต้องการข้อมูลเพิ่มเติม (เช่นข้อมูลเฉพาะเกี่ยวกับตารางและข้อมูลผลของการทดสอบที่แนะนำ ฯลฯ ) เพื่อช่วยลดสาเหตุของเวลาตอบสนอง 20-25 วินาที ที่คุณเห็น

SET ANSI_NULLS, NOCOUNT ON;
GO

IF (OBJECT_ID(N'dbo.XmlReadTest') IS NOT NULL)
BEGIN
    PRINT N'Dropping table...';
    DROP TABLE dbo.XmlReadTest;
END;

PRINT N'Creating table...';
CREATE TABLE dbo.XmlReadTest 
(
    ID INT NOT NULL IDENTITY(1, 1),
    Col2 BIGINT,
    Col3 UNIQUEIDENTIFIER,
    Col4 DATETIME,
    Col5 XML,
    CONSTRAINT [PK_XmlReadTest] PRIMARY KEY CLUSTERED ([ID])
);
GO

DECLARE @MaxSets INT = 1000,
        @CurrentSet INT = 1;

WHILE (@CurrentSet <= @MaxSets)
BEGIN
    RAISERROR(N'Populating data (1000 sets of 1000 rows); Set # %d ...',
              10, 1, @CurrentSet) WITH NOWAIT;
    INSERT INTO dbo.XmlReadTest (Col2, Col3, Col4, Col5)
        SELECT  TOP 1000
                CONVERT(BIGINT, CRYPT_GEN_RANDOM(8)),
                NEWID(),
                GETDATE(),
                N'<test>'
                  + REPLICATE(CONVERT(NVARCHAR(MAX), CRYPT_GEN_RANDOM(1), 2), 3750)
                  + N'</test>'
        FROM        [master].[sys].all_columns sac1;

    IF ((@CurrentSet % 100) = 0)
    BEGIN
        RAISERROR(N'Executing CHECKPOINT ...', 10, 1) WITH NOWAIT;
        CHECKPOINT;
    END;

    SET @CurrentSet += 1;
END;

--

SELECT COUNT(*) FROM dbo.XmlReadTest; -- Verify that we have 1 million rows

-- O.P. states that the "clustered index fragmentation is close to 0%"
ALTER INDEX [PK_XmlReadTest] ON dbo.XmlReadTest REBUILD WITH (FILLFACTOR = 90);
CHECKPOINT;

--

DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;

SET STATISTICS IO, TIME ON;
SELECT TOP 1000 * FROM dbo.XmlReadTest;
SET STATISTICS IO, TIME OFF;

/*
Scan count 1, logical reads 21,       physical reads 1,     read-ahead reads 4436,
              lob logical reads 5676, lob physical reads 1, lob read-ahead reads 3967.

 SQL Server Execution Times:
   CPU time = 171 ms,  elapsed time = 8329 ms.
*/

และเนื่องจากเราต้องการแยกเวลาที่ใช้ในการอ่านหน้าเว็บที่ไม่ใช่ LOB ฉันจึงเรียกใช้แบบสอบถามต่อไปนี้เพื่อเลือกทั้งหมดยกเว้นคอลัมน์ XML (หนึ่งในการทดสอบที่ฉันแนะนำด้านบน) ผลตอบแทนนี้ใน 1.5 วินาทีค่อนข้างสม่ำเสมอ

DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;

SET STATISTICS IO, TIME ON;
SELECT TOP 1000 ID, Col2, Col3, Col4 FROM dbo.XmlReadTest;
SET STATISTICS IO, TIME OFF;

/*
Scan count 1, logical reads 21,    physical reads 1,     read-ahead reads 4436,
              lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1666 ms.
*/

บทสรุป (สักครู่)
จากความพยายามสร้างสถานการณ์ของคุณขึ้นใหม่ฉันไม่คิดว่าเราสามารถชี้ไปที่ไดรฟ์ SATA หรือ I / O ที่ไม่ต่อเนื่องกันเป็นสาเหตุหลักของ 20-25 วินาทีโดยเฉพาะอย่างยิ่งเพราะเรายังคง ไม่ทราบว่าคิวรีส่งคืนเร็วแค่ไหนเมื่อไม่รวมคอลัมน์ XML และฉันไม่สามารถทำซ้ำการอ่านแบบลอจิคัล (ไม่ใช่ LOB) จำนวนมากที่คุณแสดงอยู่ แต่ฉันมีความรู้สึกว่าฉันต้องการเพิ่มข้อมูลเพิ่มเติมลงในแต่ละแถวด้วยเหตุนั้นและคำสั่งของ:

~ 90% ของหน้าตารางคือ LOB_DATA

ตารางของฉันมี 1 ล้านแถวแต่ละแถวมีข้อมูล XML มากกว่า 15k และsys.dm_db_index_physical_statsแสดงว่ามีหน้า LOB_DATA 2 ล้านหน้า ส่วนที่เหลืออีก 10% จะเป็นหน้าข้อมูล IN_ROW 222k แต่ฉันมีเพียง 11,630 แห่งเท่านั้น ดังนั้นอีกครั้งเราต้องการข้อมูลเพิ่มเติมเกี่ยวกับสคีมาตารางจริงและข้อมูลจริง


การสนทนานี้ได้รับการย้ายไปแชท
พอลไวท์พูดว่า GoFundMonica

10

ฉันถูกต้องแล้วโดยคิดว่าหน้า LOB_DATA สามารถทำให้การสแกนช้าไม่เพียงเพราะขนาดของมัน แต่ยังเพราะ SQL Server ไม่สามารถสแกนดัชนีคลัสเตอร์ได้อย่างมีประสิทธิภาพ

ใช่การอ่านข้อมูล LOB ที่ไม่ได้จัดเก็บในแถวจะนำไปสู่การสุ่ม IO แทนการเรียงตามลำดับ IO ตัวชี้วัดประสิทธิภาพของดิสก์ที่จะใช้ที่นี่เพื่อทำความเข้าใจว่าทำไมมันเร็วหรือช้าคือ Random Read IOPS

ข้อมูล LOB ถูกเก็บไว้ในโครงสร้างต้นไม้ที่หน้าข้อมูลในดัชนีดัชนีคลัสเตอร์ไปยังหน้าข้อมูล LOB ที่มีโครงสร้างรูต LOB ซึ่งจะชี้ไปที่ข้อมูล LOB จริง เมื่อทำการข้ามโหนดรูทในดัชนีคลัสเตอร์ SQL Server จะได้รับข้อมูลในแถวเท่านั้นโดยการอ่านตามลำดับ เพื่อให้ได้ข้อมูล LOB SQL Server ต้องไปที่อื่นบนดิสก์

ฉันเดาว่าถ้าคุณเปลี่ยนเป็นดิสก์ SSD คุณจะไม่ได้รับความทุกข์ทรมานจากสิ่งนี้มากนักเนื่องจาก IOPS แบบสุ่มสำหรับ SSD นั้นสูงกว่าดิสก์หมุน

มันถือว่าสมเหตุสมผลที่จะมีโครงสร้างตาราง / รูปแบบข้อมูลหรือไม่

ใช่มันอาจจะเป็น ขึ้นอยู่กับสิ่งที่ตารางนี้ทำเพื่อคุณ

โดยทั่วไปแล้วปัญหาประสิทธิภาพการทำงานกับ XML ใน SQL Server เกิดขึ้นเมื่อคุณต้องการใช้ T-SQL เพื่อสืบค้นลงใน XML และอีกมากดังนั้นเมื่อคุณต้องการใช้ค่าจาก XML ในเพรดิเคตในส่วนคำสั่งหรือเข้าร่วม หากเป็นกรณีนี้คุณสามารถดูที่การเลื่อนขั้นคุณสมบัติหรือดัชนี XML แบบเลือกได้หรือการออกแบบโครงสร้างตารางของคุณย่อย XML เป็นตารางย่อยแทน

ฉันพยายามบีบอัด

ฉันทำอย่างนั้นครั้งเดียวในผลิตภัณฑ์สักเล็กน้อยกว่า 10 ปีที่แล้วและรู้สึกเสียใจมาตั้งแต่นั้น ฉันพลาดจริง ๆ ไม่สามารถทำงานกับข้อมูลโดยใช้ T-SQL ดังนั้นฉันจะไม่แนะนำให้ใครถ้ามันสามารถหลีกเลี่ยงได้


ขอบคุณมากสำหรับคำตอบ เกี่ยวกับการบีบอัด: ฉันไม่แน่ใจว่าคำแนะนำการต่อต้านที่เข้มงวดนั้นมีเหตุผลหรือไม่เนื่องจากความต้องการสืบค้นข้อมูลจาก T-SQL อย่างชัดเจนนั้นขึ้นอยู่กับลักษณะของข้อมูลที่จัดเก็บไว้ ในกรณีของฉันฉันตัดสินใจที่จะไปกับการบีบอัดในตอนนี้
Alexander Shelemin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.