การแสดงตนของฟิลด์ 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 สองแบบดังนี้:
- Inline Root - สำหรับข้อมูลระหว่าง 8001 ถึง 40,000 (จริง ๆ 42,000) ไบต์การอนุญาตให้ใช้พื้นที่จะมี 1 ถึง 5 ตัวชี้ (24 - 72 ไบต์) ในแถวที่ชี้ไปยังหน้า LOB โดยตรง
- 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 ล้านแถว
- ขนาดโต๊ะประมาณ 15 GB
- ตารางที่มีหนึ่ง
XML
คอลัมน์และอีกหลายคอลัมน์อื่น ๆ ประเภท: INT
, BIGINT
, UNIQUEIDENTIFIER
"ฯลฯ"
XML
คอลัมน์ "ขนาด" คือโดยเฉลี่ยประมาณ 15k
- หลังจากทำงาน
DBCC DROPCLEANBUFFERS
แล้วจะใช้เวลา 20-25 วินาทีในการค้นหาให้เสร็จสมบูรณ์:SELECT TOP 1000 * FROM TABLE
- กำลังสแกนดัชนีแบบคลัสเตอร์
- การแตกแฟรกเมนต์ในดัชนีแบบคลัสเตอร์ใกล้เคียงกับ 0%
สิ่งที่เราคิดว่าเรารู้:
- ไม่มีกิจกรรมดิสก์อื่นนอกเหนือจากการค้นหาเหล่านี้ คุณแน่ใจไหม? แม้ว่าจะไม่มีการสอบถามผู้ใช้อื่น ๆ จะมีการดำเนินการพื้นหลังที่เกิดขึ้น? มีกระบวนการภายนอกไปยัง SQL Server ที่ทำงานบนเครื่องเดียวกันที่อาจใช้ IO บางอย่างหรือไม่ อาจไม่มี แต่ก็ไม่ชัดเจนตามข้อมูลที่ให้ไว้เท่านั้น
- กำลังส่งคืนข้อมูล XML 15 MB ตัวเลขนี้ขึ้นอยู่กับอะไร การประเมินมาจาก 1,000 แถวคูณกับค่าเฉลี่ยของข้อมูล XML 15k ต่อแถว? หรือการรวมแบบเป็นโปรแกรมของสิ่งที่ได้รับสำหรับการค้นหานั้น? หากเป็นเพียงการประมาณค่าฉันจะไม่เชื่อถือเนื่องจากการเผยแพร่ข้อมูล XML อาจไม่ได้เป็นไปในลักษณะที่ค่าเฉลี่ยโดยนัยง่าย ๆ
การบีบอัด 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
ข้อมูลนั้นมีประโยชน์ไม่เพียงพอ มีปัจจัยหลายอย่างที่มีผลต่อประสิทธิภาพการค้นหาดังนั้นเราจึงต้องการภาพที่มีรายละเอียดมากขึ้นว่าเกิดอะไรขึ้น
สิ่งที่เราไม่รู้ แต่ต้อง:
- ทำไมประสิทธิภาพของ
SELECT *
สสาร นี่เป็นรูปแบบที่คุณใช้ในรหัส ถ้าเป็นเช่นนั้นทำไม
- ประสิทธิภาพในการเลือกเฉพาะคอลัมน์ XML คืออะไร อะไรคือสถิติและระยะเวลาถ้าคุณทำเพียงแค่:
SELECT TOP 1000 XmlColumn FROM TABLE;
?
ใช้เวลาประมาณ 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)
ดังนั้นทางเลือกของเรามี จำกัด น้อยกว่าที่นี่ แต่นี่คือสิ่งที่สามารถทำได้:
- ออกกฎปัญหาเครือข่ายโดยการดำเนินการค้นหาบนเซิร์ฟเวอร์ที่รัน SQL Server ทั้งใน SSMS หรือ SQLCMD.EXE
- แยกแยะปัญหาไคลเอนต์ใน SSMS โดยไปที่ตัวเลือกการสืบค้น -> ผลลัพธ์ -> กริดและตรวจสอบตัวเลือกสำหรับ "ทิ้งผลลัพธ์หลังการดำเนินการ" โปรดทราบว่าตัวเลือกนี้จะป้องกันการแสดงผลทั้งหมดรวมถึงข้อความ แต่ยังคงมีประโยชน์ในการแยกแยะเวลาที่ใช้ SSMS ในการจัดสรรหน่วยความจำต่อแต่ละแถวแล้ววาดมันในตาราง
หรือคุณสามารถดำเนินการค้นหาผ่านทาง sqlcmd.exe -o NUL:
โดยตรงและการส่งออกที่จะไปที่ไหนเลยผ่าน:
- มีประเภทรอเกี่ยวข้องกับแบบสอบถามนี้หรือไม่ ถ้าใช่ประเภทรอคืออะไร?
คืออะไรที่เกิดขึ้นจริงขนาดของข้อมูลสำหรับ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;
- แน่นอน schema ของตาราง โปรดระบุคำสั่งแบบเต็ม
CREATE TABLE
รวมถึงดัชนีทั้งหมด
- แผนค้นหาหรือไม่ นั่นเป็นสิ่งที่คุณสามารถโพสต์ได้หรือไม่ ข้อมูลนั้นอาจจะไม่เปลี่ยนแปลงอะไรเลย แต่จะดีกว่าที่จะรู้ว่ามันจะไม่ดีไปกว่าการเดาว่ามันจะไม่ผิดและ ;-)
- มีการแตกแฟรกเมนต์ทางกายภาพ / ภายนอกในไฟล์ข้อมูลหรือไม่? ในขณะที่สิ่งนี้อาจไม่ใช่ปัจจัยใหญ่ที่นี่เนื่องจากคุณใช้ "SATA ระดับผู้บริโภค" และไม่ใช่ SSD หรือแม้แต่ Super-Expensive SATA ผลของภาคที่สั่งซื้อมาอย่างเหมาะสมจะสังเกตเห็นได้ชัดเจนขึ้นโดยเฉพาะอย่างยิ่งจำนวนภาคเหล่านั้น ที่ต้องอ่านเพิ่มขึ้น
อะไรคือผลลัพธ์ที่แน่นอนของแบบสอบถามต่อไปนี้:
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 แห่งเท่านั้น ดังนั้นอีกครั้งเราต้องการข้อมูลเพิ่มเติมเกี่ยวกับสคีมาตารางจริงและข้อมูลจริง