ประสิทธิภาพของตารางในหน่วยความจำแย่กว่าตารางแบบดิสก์


10

ฉันมีตารางใน SQL Server 2014 ที่มีลักษณะดังต่อไปนี้:

CREATE TABLE dbo.MyTable
(
[id1] [bigint] NOT NULL,
[id2] [bigint] NOT NULL,
[col1] [int] NOT NULL default(0),
[col2] [int] NOT NULL default(0)
)

ด้วย (id1, id2) เป็น PK โดยพื้นฐานแล้ว id1 เป็นตัวระบุเพื่อจัดกลุ่มชุดผลลัพธ์ (id2, col1, col2) ซึ่ง pk คือ id2

ฉันพยายามใช้ตารางในหน่วยความจำเพื่อกำจัดตารางดิสก์ที่มีอยู่ซึ่งเป็นคอขวดของฉัน

  • ข้อมูลในตารางถูกเขียน -> อ่าน -> ลบหนึ่งครั้ง
  • ค่า id1 แต่ละค่ามี id2 หลาย (หลายสิบ /))
  • ข้อมูลจะถูกเก็บไว้ในตารางเป็นเวลาสั้น ๆ เช่น 20 วินาที

แบบสอบถามที่ดำเนินการในตารางนี้มีดังต่อไปนี้:

-- INSERT (can vary from 10s to 10,000s of records):
INSERT INTO MyTable
  SELECT @fixedValue, id2, col1, col2 FROM AnotherTable

-- READ:
SELECT id2, col1
FROM MyTable INNER JOIN OtherTbl ON MyTable.id2 = OtherTbl.pk
WHERE id1 = @value
ORDER BY col1

-- DELETE:
DELETE FROM MyTable WHERE id1 = @value

นี่คือคำจำกัดความปัจจุบันที่ฉันใช้สำหรับตาราง:

CREATE TABLE dbo.SearchItems
(
  [id1] [bigint] NOT NULL,
  [id2] [bigint] NOT NULL,
  [col1] [int] NOT NULL default(0),
  [col2] [int] NOT NULL default(0)

  CONSTRAINT PK_Mem PRIMARY KEY NONCLUSTERED (id1,id2),
  INDEX idx_Mem HASH (id1,id2) WITH (BUCKET_COUNT = 131072)
) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY)

น่าเสียดายที่คำจำกัดความนี้ส่งผลให้ประสิทธิภาพลดลงตามสถานการณ์ก่อนหน้านี้ด้วยตารางบนดิสก์ ลำดับของขนาดสูงกว่าหรือน้อยกว่า 10% (ในบางกรณีถึง 100% ดังนั้นเวลาสองเท่า)

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

คำถาม:

  • BUCKET_COUNT ที่ถูกต้องที่จะตั้งคืออะไร
  • ฉันควรใช้ดัชนีประเภทใด
  • เหตุใดประสิทธิภาพจึงแย่กว่าตารางที่ใช้ดิสก์

แบบสอบถามของsys.dm_db_xtp_hash_index_statsส่งคืน:

total_bucket_count = 131072
empty_bucket_count = 0
avg_chain_len = 873
max_chain_length = 1009

ฉันเปลี่ยนจำนวนที่ฝากข้อมูลดังนั้นผลลัพธ์จากsys.dm_db_xtp_hash_index_statsคือ:

total_bucket_count = 134217728
empty_bucket_count = 131664087
avg_chain_len = 1
max_chain_length = 3

ถึงกระนั้นผลลัพธ์ก็เกือบจะเหมือนกันหากไม่ได้แย่ลง


แน่ใจหรือไม่ว่าคุณไม่ได้พบกับการดมกลิ่นพารามิเตอร์ คุณลองเรียกใช้คิวรีด้วยOPTION(OPTIMIZE FOR UNKNOWN)(ดูคำแนะนำตาราง ) หรือไม่
TT

ฉันเดาว่าคุณกำลังประสบปัญหาเรื่องลูกโซ่แถว คุณช่วยให้เราส่งออกของselect * from sys.dm_db_xtp_hash_index_stats ? นอกจากนี้ลิงก์นี้ควรตอบคำถามของคุณมากที่สุด / ทั้งหมด: msdn.microsoft.com/en-us/library/ ......
Sean Gallardy

4
ดัชนีแฮชมีประโยชน์สำหรับเพรดิเคตในคอลัมน์ที่รวมอยู่ทั้งสองเท่านั้น คุณเคยลองโดยไม่มีดัชนีแฮชบนโต๊ะหรือไม่?
Mikael Eriksson

ฉันพบว่าการปรับปรุงประสิทธิภาพที่ดีที่สุดด้วยเทคโนโลยีในหน่วยความจำสามารถทำได้โดยใช้วิธีการเก็บรวบรวมแบบดั้งเดิม
Daniel Hutmacher

@DanielHutmacher FWIW ฉันเคยเห็นตัวอย่างการตอบโต้ที่ผลประโยชน์ทั้งหมดมาจากการลบ latching และการเพิ่มขั้นตอนการคอมไพล์แบบดั้งเดิมทำให้การปรับปรุงเป็นศูนย์หรือเล็กน้อย ฉันไม่คิดว่าจะมีห้องว่างสำหรับงบแบบครอบคลุม (แม้ว่าคุณอาจจะถูกในกรณีนี้ฉันยังไม่ได้ดูรายละเอียด)
Aaron Bertrand

คำตอบ:


7

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

น่าเสียดายที่คำจำกัดความนี้ส่งผลให้ประสิทธิภาพลดลงตามสถานการณ์ก่อนหน้านี้ด้วยตารางบนดิสก์ ลำดับของขนาดสูงกว่าหรือน้อยกว่า 10% (ในบางกรณีถึง 100% ดังนั้นเวลาสองเท่า)

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

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

แต่เดิมฉันคิดมากเกี่ยวกับคำถามของคุณเกี่ยวกับเรื่องนี้:

คำถาม:

  • BUCKET_COUNT ที่ถูกต้องที่จะตั้งคืออะไร
  • ฉันควรใช้ดัชนีประเภทใด
  • เหตุใดประสิทธิภาพจึงแย่กว่าตารางที่ใช้ดิสก์

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

-- INSERT (can vary from 10s to 10,000s of records):
INSERT INTO MyTable
  SELECT @fixedValue, id2, col1, col2 FROM AnotherTable

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

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

ด้วยแบบสอบถามเลือก:

SELECT id2, col1
FROM MyTable INNER JOIN OtherTbl ON MyTable.id2 = OtherTbl.pk
WHERE id1 = @value
ORDER BY col1

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

เพื่อให้ข้อเท็จจริงตามการวิจัยจริง ๆ ฉันได้โหลดSearchItemsตารางหน่วยความจำที่มี 10 ล้านแถวและAnotherTable100,000 เพราะฉันไม่ทราบขนาดหรือสถิติที่แท้จริงของมัน ฉันใช้แบบสอบถามแบบเลือกด้านบนเพื่อดำเนินการ นอกจากนี้ฉันสร้างเซสชันเพิ่มเติมของกิจกรรมบน wait_completed และใส่ลงในบัฟเฟอร์วงแหวน มันถูกทำความสะอาดหลังการวิ่งแต่ละครั้ง ฉันยังวิ่งDBCC DROPCLEANBUFFERSไปจำลองสภาพแวดล้อมที่ข้อมูลทั้งหมดอาจไม่อยู่ในหน่วยความจำ

ผลลัพธ์ไม่ได้มีอะไรน่าตื่นเต้นเมื่อมองดูพวกเขาในสุญญากาศ เนื่องจากแล็ปท็อปที่ฉันกำลังทดสอบนี้ใช้ SSD ระดับสูงกว่าฉันจึงลดประสิทธิภาพการทำงานของดิสก์ลงสำหรับ VM ที่ฉันใช้

ผลลัพธ์ที่ได้นั้นมาพร้อมกับข้อมูลที่ไม่ต้องรอหลังจากทำการสืบค้น 5 ครั้งบนตารางที่อยู่ในหน่วยความจำ (ลบการเข้าร่วมและไม่มีการสืบค้นย่อย) นี่มันสวยมากอย่างที่คาดไว้

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

ในกรณีนี้อีกครั้งส่วนเวลาที่สำคัญถูกใช้ในตารางตามดิสก์

ในที่สุดแบบสอบถามลบ การค้นหาแถวที่อิงจาก ID1 นั้นไม่ได้มีประสิทธิภาพมากนักเมื่อมีดัชนี ในขณะที่มันเป็นความจริงที่ภาคแสดงความเท่าเทียมกันเป็นสิ่งที่ดัชนีแฮชเหมาะสมสำหรับถังข้อมูลที่อยู่ในนั้นขึ้นอยู่กับคอลัมน์ที่แฮชทั้งหมด ดังนั้น id1, id2 โดยที่ id1 = 1, id2 = 2 และ id1 = 1, id2 = 3 จะถูกแฮ็กเข้าไปในที่เก็บข้อมูลที่แตกต่างกันเนื่องจากแฮชจะข้าม (1,2) และ (1,3) นี่จะไม่ใช่การสแกนช่วง B-Tree อย่างง่ายเนื่องจากดัชนีแฮชไม่ได้มีโครงสร้างแบบเดียวกัน ฉันคาดหวังว่าสิ่งนี้จะไม่เป็นดัชนีในอุดมคติสำหรับการดำเนินการนี้ แต่ฉันไม่คาดหวังว่าจะได้รับคำสั่งที่มีขนาดยาวกว่าที่มีประสบการณ์ ฉันสนใจที่จะเห็น wait_info เกี่ยวกับเรื่องนี้

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

ในขณะที่มันเป็นความจริงที่ใช้ล็อคเพื่อความมั่นคงตรรกะการดำเนินการจะต้องยังคงเป็นอะตอม สิ่งนี้ทำผ่านตัวดำเนินการเปรียบเทียบ CPU แบบพิเศษ (ซึ่งเป็นสาเหตุที่ In-Memory ทำงานได้เฉพาะกับ [บางตัวแม้ว่าซีพียูเกือบทุกตัวที่ทำใน 4 ปีที่ผ่านมา]) ดังนั้นเราจะไม่ได้รับทุกอย่างฟรีจะมีเวลาในการดำเนินการเหล่านี้ให้เสร็จ

อีกประเด็นที่จะนำมาเป็นความจริงที่ว่าในเกือบทุกแบบสอบถามที่ใช้อินเตอร์เฟซที่เป็น T-SQL (และไม่ได้รวบรวม SPROCs) ซึ่งสัมผัสอย่างน้อยหนึ่งตารางตามดิสก์ นี่คือเหตุผลที่ฉันเชื่อว่าในท้ายที่สุดเราไม่ได้มีประสิทธิภาพเพิ่มขึ้นจริง ๆ เพราะเรายังคง จำกัด ประสิทธิภาพของตารางที่ใช้ดิสก์

ติดตาม:

  1. สร้างเซสชันเหตุการณ์เพิ่มเติมสำหรับ wait_completed และระบุ SPID ที่คุณรู้จัก เรียกใช้แบบสอบถามและให้ผลลัพธ์กับเราหรือใช้ภายใน

  2. ให้เราอัปเดตเกี่ยวกับผลลัพธ์จาก # 1

  3. ไม่มีหมายเลขเวทมนต์สำหรับการพิจารณาจำนวนนับสำหรับดัชนีแฮช โดยทั่วไปตราบใดที่ถังไม่เต็มและโซ่แถวอยู่ต่ำกว่า 3 หรือ 4 ประสิทธิภาพควรอยู่ในระดับที่ยอมรับได้ นี่เป็นการถามแบบ "ฉันควรตั้งค่าไฟล์บันทึกของฉันเป็นอย่างไร" - มันจะขึ้นอยู่กับกระบวนการต่อฐานข้อมูลต่อประเภทการใช้งาน

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