ค้นหาขนาดที่ไม่บีบอัดของตารางทั้งหมดในฐานข้อมูล


12

ใน Dynamics AX มีกลไกการแคชซึ่งสามารถกำหนดตารางให้โหลดลงในหน่วยความจำและแคชได้ แคชนี้ จำกัด จำนวน KB ไว้เพื่อป้องกันปัญหาหน่วยความจำ การตั้งค่าที่ฉันกำลังพูดถึงถูกเรียกentiretablecacheและโหลดทั้งตารางในหน่วยความจำทันทีที่มีการร้องขอบันทึกเดียว

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

อย่างไรก็ตามตอนนี้การบีบอัดเริ่มเข้ามาเล่นและสิ่งต่าง ๆ เช่นsp_spaceusedหรือsys.allocation_unitsดูเหมือนจะรายงานพื้นที่ที่ใช้จริงโดยข้อมูลที่บีบอัด

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

ฉันรู้เกี่ยวกับsp_estimate_data_compression_savingsแต่อย่างที่ชื่อบอกนี่เป็นเพียงการประมาณ
ฉันต้องการมีขนาดที่ถูกต้องที่สุด

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

Powershell อาจเป็นตัวเลือก แต่ฉันไม่ต้องการวนซ้ำทุกตารางเพื่อดำเนินการselect *กับพวกเขาเพื่อตรวจสอบขนาดในสคริปต์เนื่องจากอาจทำให้แคชล้นและอาจใช้เวลานานเกินไป

กล่าวโดยย่อฉันต้องการวิธีเพิ่มขนาดสำหรับแต่ละตารางเนื่องจากจะไม่มีการบีบอัดและมีการแตกแฟรกเมนต์ออกมาจากสมการที่นำเสนอไปยังแอปพลิเคชันหากเป็นไปได้ ฉันเปิดกว้างกับแนวทางที่แตกต่างกัน T-SQL เป็นที่ต้องการมากกว่า แต่ฉันไม่ได้ต่อต้าน Powershell หรือวิธีการสร้างสรรค์อื่น ๆ

สมมติว่าบัฟเฟอร์ในแอปพลิเคชันคือขนาดของข้อมูล bigint มักมีขนาดเท่ากับ bigint เสมอและประเภทข้อมูลอักขระคือ 2 ไบต์ต่ออักขระ (unicode) ข้อมูล BLOB ก็ใช้ขนาดของข้อมูลด้วยเช่นกัน Enum นั้นโดยทั่วไปแล้วข้อมูลที่เป็นตัวเลขและตัวเลขคือตัวเลข (38,12) datetime คือขนาดของวันที่และเวลา นอกจากนี้ยังไม่มีNULLค่าจะถูกเก็บเป็นสตริงว่าง1900-01-01หรือศูนย์

ไม่มีเอกสารเกี่ยวกับวิธีการใช้งานนี้ แต่ข้อสันนิษฐานนั้นมาจากการทดสอบและสคริปต์ที่ใช้โดย PFE's และทีมสนับสนุน (ซึ่งไม่สนใจการบีบอัดด้วยเนื่องจากการตรวจสอบถูกสร้างขึ้นในแอปพลิเคชันและแอปไม่สามารถบอกได้ ถ้าข้อมูลพื้นฐานถูกบีบอัด) ซึ่งตรวจสอบขนาดตารางด้วย ลิงค์นี้สำหรับสถานะตัวอย่าง:

หลีกเลี่ยงการใช้แคช EntireTable สำหรับตารางขนาดใหญ่ (ใน AX 2009 มากกว่า 128 KB หรือ 16 หน้าใน AX 2012 เหนือการตั้งค่าแอปพลิเคชัน 'ขนาดแคชของตารางทั้งหมด' [ค่าเริ่มต้น: 32KB หรือ 4 หน้า]) - ย้ายเพื่อบันทึกแคชแทน


3
มันเป็นเรื่องแฮ็ก แต่บางทีสำเนาที่กู้คืนพร้อมการบีบอัดจะถูกปิดใช้งานอย่างแม่นยำที่สุด จากนั้นคุณกำลังทดสอบการกู้คืนซึ่งทำให้คุณดูเหมือนติดอันดับ 1 DBA
Erik Darling

เชื่อว่านั่นจะเป็นทางออกที่ดีที่สุดของคุณ อาจมีวิธีการเรียงลำดับของการลองและทำคณิตศาสตร์ จำนวนแถวตามชนิดข้อมูลและความยาวคอลัมน์ที่กำหนดที่คูณและเพิ่มในดัชนี ฯลฯ มันทำงานได้ดีกว่าการเขียนสคริปต์การกู้คืนและปิดใช้งานการบีบอัด @sp_BlitzErik ที่แนะนำข้างต้น และใครที่ไม่ต้องการเป็นอันดับ 1 DBA
Mike Walsh

SUM (ความยาวของข้อมูล) สำหรับคอลัมน์ทั้งหมดได้รับขนาดข้อมูลที่ไม่บีบอัดหรือไม่
Tapakah Ua

@sp_BlitzErik นั่นอาจเป็นคำตอบแทนที่จะเป็นความคิดเห็น
Tom V - ลอง topanswers.xyz

คำตอบ:


7

ฉันต้องการขนาดจริงข้อมูลที่ไม่มีการบีบอัดจะมี
...
ฉันต้องการมีขนาดที่ถูกต้องที่สุด

ในขณะที่ความต้องการข้อมูลนี้เป็นที่เข้าใจอย่างแน่นอนการได้รับข้อมูลนี้โดยเฉพาะอย่างยิ่งในบริบทของ "การแก้ไขที่ถูกต้องที่สุด" นั้นมีความซับซ้อนกว่าที่ทุกคนคาดหวังเนื่องจากข้อสันนิษฐานที่ผิดพลาด ไม่ว่าจะทำแนวคิดเงาตารางที่ไม่มีการบีบอัดที่กล่าวถึงในคำถามหรือคำแนะนำของ @ sp_BlitzErik ในความคิดเห็นเกี่ยวกับการกู้คืนฐานข้อมูลและการบีบอัดที่นั่นเพื่อตรวจสอบไม่ควรสันนิษฐานว่าขนาดของตารางที่ไม่มีการบีบอัด == ขนาดของข้อมูลดังกล่าวในหน่วยความจำ บนเซิร์ฟเวอร์แอป:

  1. กำลังทุกแถวในตารางที่ถูกเก็บไว้ชั่วคราว? หรือเพียงแค่อยู่ในช่วง? สมมติฐานที่นี่คือมันคือทั้งหมดและที่อาจจะถูกต้อง แต่ฉันคิดว่าอย่างน้อยก็ควรได้รับการกล่าวถึงว่านี่อาจจะไม่เป็นกรณี (เว้นแต่เอกสารประกอบฯ เป็นอย่างอื่น แต่นี่เป็นจุดรองอยู่แล้วก็ไม่ต้องการ ไม่ต้องพูดถึง)

    คำถามได้รับการอัปเดตเป็นสถานะ: ใช่แถวทั้งหมดจะถูกแคช

  2. โครงสร้างค่าใช้จ่าย

    1. ในด้าน DB:
      หน้าและค่าใช้จ่ายแถวในด้าน DB: จำนวนแถวที่พอดีกับหน้าจะถูกกำหนดโดยปัจจัยหลายอย่างที่สามารถสลัดประมาณการ แม้ว่าจะมีFILLFACTOR100 (หรือ 0) แต่ก็ยังมีพื้นที่ว่างที่ไม่ได้ใช้เหลืออยู่บนหน้าเนื่องจากมีพื้นที่ไม่พอสำหรับทั้งแถว และนอกเหนือจากส่วนหัวของหน้า นอกจากนี้หากเปิดใช้งานฟังก์ชั่น Snapshot Isolation ผมเชื่อว่าจะมีการเพิ่มหมายเลขรุ่น 13 ไบต์ต่อแถวด้วยหมายเลขรุ่นและจะทำให้การประมาณการลดลง มี minutia อื่น ๆ ที่เกี่ยวข้องกับขนาดที่แท้จริงของแถว (บิตแมป NULL, คอลัมน์ความยาวแปรปรวน, ฯลฯ ) แต่รายการที่กล่าวถึงป่านนี้ควรทำให้จุดเดียว
    2. ที่ฝั่งเซิร์ฟเวอร์แอป:
      การรวบรวมประเภทใดที่ใช้ในการจัดเก็บผลการแคช ฉันถือว่านี่เป็นแอป. NET ดังนั้นจะเป็นDataTableอย่างไร รายการทั่วไป? พจนานุกรมการเรียงลำดับ? การรวบรวมแต่ละประเภทมีจำนวนได้ยินที่แตกต่างกัน ฉันไม่คาดหวังว่าตัวเลือกใด ๆ ในการสะท้อนค่าโสหุ้ยของหน้าและแถวในด้าน DB โดยเฉพาะอย่างยิ่งในระดับ (ฉันแน่ใจว่าจำนวนแถวขนาดเล็กอาจไม่มีความหลากหลายพอที่จะสำคัญ แต่คุณไม่ได้มองหาความแตกต่าง ในหลายร้อยไบต์หรือเพียงไม่กี่กิโลไบต์)
  3. ประเภทข้อมูล
    1. ที่ด้าน DB:
      CHAR/ VARCHARdata ถูกเก็บไว้ที่ 1 ไบต์ต่อตัวอักษร (ละเว้นอักขระสองไบต์ในขณะนี้) XMLได้รับการปรับให้เหมาะสมที่จะไม่ใช้พื้นที่มากเท่ากับการแสดงข้อความ ประเภทข้อมูลนี้สร้างพจนานุกรมขององค์ประกอบและชื่อแอตทริบิวต์และแทนที่การอ้างอิงจริงไปยังพวกเขาในเอกสารด้วยรหัสที่เกี่ยวข้องของพวกเขา (ค่อนข้างดีจริง) มิฉะนั้นค่าสตริงที่มีทั้งหมด UTF-16 (2 หรือ 4 ไบต์ต่อ "ตัวอักษร") เช่นเดียว/NCHAR อยู่ระหว่าง 6 ถึง 8 ไบต์ อยู่ระหว่าง 5 ถึง 17 ไบต์ (ขึ้นอยู่กับความแม่นยำ)NVARCHARDATETIME2DECIMAL
    2. ที่ฝั่งเซิร์ฟเวอร์แอป:
      สตริง (อีกครั้งสมมติว่า. NET) เป็น UTF-16 เสมอ ไม่มีการปรับให้เหมาะสมสำหรับสตริง 8 บิตเช่นที่VARCHARมีอยู่ แต่สตริงยังสามารถ "interned" ซึ่งเป็นสำเนาที่แชร์ซึ่งสามารถอ้างอิงได้หลายครั้ง (แต่ฉันไม่รู้ว่ามันใช้งานได้กับสตริงในคอลเลกชันหรือไม่ถ้ามันใช้ได้กับคอลเลกชันทุกประเภท) XMLอาจหรืออาจไม่ถูกจัดเก็บในลักษณะเดียวกันในหน่วยความจำ (ฉันจะต้องดูว่าขึ้น) DateTimeอยู่เสมอ 8 ไบต์ (เช่น T-SQL DATETIMEแต่ไม่ชอบDATE, TIMEหรือDATETIME2) Decimalมีขนาด 16 ไบต์เสมอ

จากข้อมูลทั้งหมดที่กล่าวมา: ไม่มีอะไรที่คุณสามารถทำได้บนฝั่ง DB เพื่อให้ได้ขนาดหน่วยความจำที่แม่นยำพอสมควรในฝั่งเซิร์ฟเวอร์แอป คุณต้องหาวิธีในการสอบถามเซิร์ฟเวอร์แอปเองหลังจากที่โหลดด้วยตารางเฉพาะแล้วดังนั้นควรรู้ว่ามันใหญ่แค่ไหน และฉันไม่แน่ใจว่าดีบักเกอร์จะช่วยให้คุณเห็นขนาดรันไทม์ของคอลเลกชันที่เต็มไปหรือไม่ ถ้าไม่เช่นนั้นวิธีเดียวที่จะเข้าใกล้คือเข้าแถวทั้งหมดของตารางคูณแต่ละคอลัมน์ด้วยขนาด. NETที่เหมาะสม(เช่นINT= * 4, VARCHAR= DATALENGTH() * 2, NVARCHAR= DATALENGTH(), XML= 🙃, ฯลฯ ) แต่ยังคงทิ้งคำถามไว้ ของค่าใช้จ่ายของคอลเลกชันบวกแต่ละองค์ประกอบของคอลเลกชัน

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

SELECT
   SUM( DATALENGTH([NVarcharColumn_1]) + DATALENGTH([NVarcharColumn_N]) ) + 
   SUM( (DATALENGTH([VarcharColumn_1]) + DATALENGTH([VarcharColumn_N])) * 2 ) + 
   SUM(4 * [number_of_INT_columns]) +
   SUM(8 * [number_of_BIGINT_and_DATETIME_columns]) +
   SUM(16 * [number_of_DECIMAL/NUMERIC_and_UNIQUEIDENTIFIER_columns]) +
   etc..
FROM [SchemaName].[TableName] WITH (NOLOCK) -- assuming no Snapshot Isolation

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


เราลงเอยด้วยการนำการตรวจสอบในรหัสไปใช้เพื่อให้แน่ใจว่ามีขนาดบัฟเฟอร์ตามที่แสดงในแอปพลิเคชัน
Tom V - ลอง topanswers.xyz

6

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

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

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

  1. หากตารางมีชนิดข้อมูลแบบคงที่เท่านั้น (ไม่มีสตริงหรือ blobs) คุณสามารถประมาณจำนวนแถวโดยดูที่sys.partitionsและคำนวณขนาดของตารางโดยใช้คำจำกัดความของคอลัมน์
  2. หากตารางที่มีแถวจำนวนมากมีคอลัมน์ชนิดข้อมูลคงที่เพียงพอคุณอาจสามารถกำจัดมันใหญ่เกินไปโดยไม่ต้องดูข้อมูล ยกตัวอย่างเช่นตารางที่มี 10 ล้านแถวและ 5 BIGINTคอลัมน์อาจมีขนาดของข้อมูลที่เป็นขนาด * 10000000 (8 + 8 + 8 + 8 + 8) = 400 M Sไบต์ซึ่งอาจจะมีขนาดใหญ่กว่าขีด จำกัด ของขนาดแคชของคุณ ไม่สำคัญว่าจะมีคอลัมน์สตริงจำนวนมากเช่นกัน
  3. หากตารางที่มีไม่กี่แถวมีขนาดเล็กพอคุณอาจสามารถยืนยันได้ว่ามันต่ำกว่าขีด จำกัด เพียงโดยสมมติว่าแต่ละชนิดข้อมูลแบบไดนามิกมีขนาดสูงสุดที่เป็นไปได้ ตัวอย่างเช่นตาราง 100 แถวที่มีBIGINTคอลัมน์และNVARCHAR(20)คอลัมน์อาจไม่เกิน 100 * (8 + 2 * 20) = 4800 ไบต์
  4. อาจเป็นจริงได้ว่าหากตารางมีขนาดที่บีบอัดใน SQL Server ซึ่งมีขนาดใหญ่กว่าด้วยปัจจัยบางSอย่างที่ไม่น่าจะเหมาะสมกับแคชมากนัก คุณต้องทำการทดสอบเพื่อหาว่ามีค่าดังกล่าวอยู่หรือไม่
  5. คุณสามารถโชคดีได้ว่าคอลัมน์แบบไดนามิกทั้งหมดมีสถิติอยู่ สถิติมีข้อมูลเกี่ยวกับความยาวเฉลี่ยและอาจแม่นยำพอสำหรับวัตถุประสงค์ของคุณ

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

ต่อไปนี้เป็นแนวคิดสำหรับการทำแบบสอบถามที่ดูข้อมูลตารางได้เร็วขึ้น:

  1. สำหรับตารางขนาดใหญ่คุณสามารถใช้งานได้TABLESAMPLEตราบเท่าที่ขนาดตัวอย่างของคุณมีขนาดใหญ่พอ
  2. สำหรับตารางขนาดใหญ่ที่มีคีย์คลัสเตอร์อาจเป็นประโยชน์ในการประมวลผลตารางเป็นชุดในคีย์คลัสเตอร์ น่าเสียดายที่ฉันไม่ทราบวิธีการคำนวณค่าSUM()ที่เลิกก่อนกำหนดตามมูลค่าของการรวมนั้น ROW_NUMBER()ผมเคยเห็นเท่านั้นที่เคยทำงานที่ แต่คุณสามารถสแกน 10% แรกของตารางบันทึกขนาดข้อมูลจากการคำนวณสแกน 10% ถัดไปและอื่น ๆ สำหรับตารางที่มีขนาดใหญ่เกินไปสำหรับแคชคุณอาจสามารถบันทึกจำนวนงานที่สำคัญด้วยวิธีนี้โดยการออกจากต้น
  3. สำหรับบางตารางคุณอาจโชคดีพอที่จะครอบคลุมดัชนีในคอลัมน์ไดนามิกทั้งหมด ขึ้นอยู่กับขนาดของแถวหรือปัจจัยอื่น ๆ ที่สแกนแต่ละดัชนีในแต่ละครั้งอาจเร็วกว่าการสแกนตาราง คุณสามารถออกจากกระบวนการนี้ก่อนได้หากขนาดตารางใหญ่เกินไปหลังจากอ่านดัชนีในคอลัมน์เดียว
  4. ความยาวเฉลี่ยของคอลัมน์แบบไดนามิกของคุณอาจไม่เปลี่ยนแปลงตลอดเวลา อาจเป็นประโยชน์ในการบันทึกความยาวเฉลี่ยที่คุณคำนวณและใช้ค่าเหล่านั้นในการคำนวณของคุณชั่วขณะหนึ่ง คุณสามารถรีเซ็ตค่าเหล่านี้ตามกิจกรรม DML ในตารางหรืออิงจากตัวชี้วัดอื่น ๆ
  5. หากเป็นไปได้ที่จะทำการทดสอบบนตารางทั้งหมดเพื่อพัฒนาอัลกอริทึมคุณอาจสามารถใช้ประโยชน์จากรูปแบบในข้อมูลได้ ตัวอย่างเช่นหากคุณประมวลผลตารางที่เริ่มต้นด้วยค่าที่เล็กที่สุดก่อนคุณอาจพบว่าเมื่อคุณประมวลผลตาราง 10 (ฉันทำตัวเลขนี้ขึ้นมา) ในแถวที่มีขนาดใหญ่เกินไปสำหรับแคช ขุมทรัพย์ สิ่งนี้อาจยอมรับได้หากไม่รวมตารางบางอย่างที่อาจมีอยู่ในแคช

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


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