ถ้าไม่แน่ใจว่ามันเป็นข้อผิดพลาดต่อ seแต่ก็แน่นอนที่เกิดขึ้นที่น่าสนใจ การสร้างพาร์ติชันออนไลน์ใหม่เป็นสิ่งใหม่ใน SQL Server 2014 ดังนั้นอาจมี internals บางส่วนที่จะเรียงลำดับตามสิ่งนี้
นี่คือคำอธิบายที่ดีที่สุดของฉันสำหรับคุณ สถิติที่เพิ่มขึ้นจำเป็นต้องมีการสุ่มตัวอย่างพาร์ติชั่นทั้งหมดในอัตราเดียวกันดังนั้นเมื่อเอ็นจิ้นรวมหน้าสถิติมันสามารถมั่นใจได้ว่าการกระจายตัวอย่างนั้นเปรียบได้ REBUILD
จำเป็นต้องใช้ข้อมูลตัวอย่างในอัตราตัวอย่าง 100% ไม่มีการรับประกันว่าอัตราตัวอย่าง 100% ในพาร์ติชัน 9 จะเป็นอัตราตัวอย่างที่แน่นอนของพาร์ติชั่นที่เหลืออยู่เสมอ ด้วยเหตุนี้มันจึงดูเหมือนว่าเอ็นจิ้นไม่สามารถรวมตัวอย่างได้และคุณจะจบลงด้วยสถิติหยดเปล่า อย่างไรก็ตามวัตถุสถิติยังคงอยู่ที่นั่น:
select
check_time = sysdatetime(),
schema_name = sh.name,
table_name = t.name,
stat_name = s.name,
index_name = i.name,
stats_column = index_col(quotename(sh.name)+'.'+quotename(t.name),s.stats_id,1),
s.stats_id,
s.has_filter,
s.is_incremental,
s.auto_created,
sp.last_updated,
sp.rows,
sp.rows_sampled,
sp.unfiltered_rows,
modification_counter
from sys.stats s
join sys.tables t
on s.object_id = t.object_id
join sys.schemas sh
on t.schema_id = sh.schema_id
left join sys.indexes i
on s.object_id = i.object_id
and s.name = i.name
outer apply sys.dm_db_stats_properties(s.object_id, s.stats_id) sp
where t.name = 'TransactionHistory' and sh.name = 'dbo'
คุณสามารถเติมหยดผ่านวิธีการใด ๆ :
UPDATE STATISTICS dbo.TransactionHistory (IDX_ProductId) WITH RESAMPLE;
หรือ
UPDATE STATISTICS dbo.TransactionHistory (IDX_ProductId) WITH RESAMPLE ON PARTITIONS (9);
หรือคุณสามารถรอให้ AutoStats อัปเดตในการคอมไพล์ครั้งแรกของแผนแบบสอบถามโดยใช้วัตถุนั้น:
-- look at my creative query
select *
from dbo.TransactionHistory
where TransactionDate = '20140101';
ต้องบอกว่าทั้งหมดนี้โพสต์ enlightening โดย Erin Stellatoเน้นสิ่งที่ได้รับการมองว่าเป็นข้อบกพร่องที่สำคัญของสถิติที่เพิ่มขึ้น ข้อมูลระดับพาร์ติชันไม่ได้ถูกใช้โดยเครื่องมือเพิ่มประสิทธิภาพในการสร้างแผนแบบสอบถามซึ่งช่วยลดผลประโยชน์ที่สันนิษฐานไว้จากสถิติส่วนเพิ่ม อะไรคือประโยชน์ปัจจุบันของสถิติที่เพิ่มขึ้น? ฉันขอเสนอว่ายูทิลิตี้หลักของพวกเขาคือความสามารถในการสุ่มตัวอย่างตารางขนาดใหญ่อย่างสม่ำเสมอในอัตราที่สูงกว่าด้วยสถิติแบบดั้งเดิม
โดยใช้ตัวอย่างของคุณนี่คือลักษณะที่ปรากฏ:
set statistics time on;
update statistics dbo.TransactionHistory(IDX_ProductId)
with fullscan;
--SQL Server Execution Times:
-- CPU time = 94 ms, elapsed time = 131 ms.
update statistics dbo.TransactionHistory(IDX_ProductId)
with resample on partitions(2);
--SQL Server Execution Times:
-- CPU time = 0 ms, elapsed time = 5 ms.
drop index IDX_ProductId On dbo.TransactionHistory;
CREATE NONCLUSTERED INDEX IDX_ProductId ON dbo.TransactionHistory (ProductId)
WITH (DATA_COMPRESSION = ROW)
ON [PRIMARY]
update statistics dbo.TransactionHistory(IDX_ProductId)
with fullscan;
--SQL Server Execution Times:
-- CPU time = 76 ms, elapsed time = 66 ms.
สถิติการสแกนแบบเต็มเกี่ยวกับค่าใช้จ่ายทางสถิติที่เพิ่มขึ้น 131 มิลลิวินาที การอัพเดตสถิติ fullscan เกี่ยวกับสถิติที่ไม่จัดแนวพาร์ติชัน 66 ms สถิติที่ไม่จัดแนวช้ากว่ามากที่สุดเนื่องจากค่าใช้จ่ายที่เกิดขึ้นจากการรวมหน้าสถิติแต่ละหน้ากลับเข้าไปในฮิสโตแกรมหลัก. อย่างไรก็ตามการใช้ออบเจกต์สถิติที่จัดเรียงพาร์ติชันเราสามารถอัปเดตพาร์ติชันหนึ่งและรวมกลับเข้าไปในฮิสโทแกรมหลักใน 5 ms ดังนั้น ณ จุดนี้ผู้ดูแลระบบที่มีสถิติที่เพิ่มขึ้นจะต้องเผชิญกับการตัดสินใจ พวกเขาสามารถลดเวลาการบำรุงรักษาสถิติโดยรวมได้โดยการอัพเดตพาร์ติชันที่จำเป็นต้องได้รับการอัพเดตแบบดั้งเดิมเท่านั้นหรือพวกเขาสามารถทดสอบด้วยอัตราตัวอย่างที่สูงขึ้นเพื่อที่พวกเขาจะได้รับแถวตัวอย่างเพิ่มเติมในช่วงเวลาเดียวกัน อดีตอนุญาตให้ห้องหายใจในหน้าต่างการบำรุงรักษาหลังอาจดันสถิติในตารางที่มีขนาดใหญ่มากไปยังสถานที่ที่แบบสอบถามได้รับแผนการที่ดีขึ้นตามสถิติที่แม่นยำยิ่งขึ้น นี่ไม่ใช่การรับประกันและไมล์สะสมของคุณอาจแตกต่างกันไป
ผู้อ่านจะเห็นว่า 66 ms ไม่ใช่เวลาอัปเดตสถิติอันเจ็บปวดในตารางนี้ดังนั้นฉันจึงลองตั้งค่าการทดสอบกับชุดข้อมูล stackexchange มีโพสต์ 6,418,608 โพสต์ (ยกเว้นโพสต์ StackOverflow และโพสต์ทั้งหมดจาก 2012 - ข้อผิดพลาดข้อมูลในส่วนของฉัน) ในการถ่ายโอนข้อมูลล่าสุดที่ฉันดาวน์โหลด
ฉันแบ่งพาร์ติชันข้อมูลโดย[CreationDate]
เพราะ ... สาธิต
ต่อไปนี้เป็นเวลาสำหรับสถานการณ์มาตรฐานที่สวยงาม (100% - การสร้างดัชนีใหม่ค่าเริ่มต้น - สถิติอัปเดตอัตโนมัติหรือUPDATE STATISTICS
ไม่มีอัตราตัวอย่างที่ระบุ:
- สร้างสถิติที่ไม่เพิ่มขึ้นด้วย Fullscan: เวลา CPU = 23500 ms, เวลาที่ผ่านไป = 22521 ms
- สร้างสถิติที่เพิ่มขึ้นด้วย Fullscan: เวลา CPU = 20406 ms, เวลาที่ผ่านไป = 15413 ms
- อัปเดตสถิติที่ไม่เพิ่มขึ้นด้วยอัตราตัวอย่างเริ่มต้น: เวลา CPU = 406 ms, เวลาที่ผ่านไป = 408 ms
- อัปเดตสถิติส่วนเพิ่มด้วยอัตราตัวอย่างเริ่มต้น: เวลา CPU = 453 ms, เวลาที่ผ่านไป = 507 ms
สมมติว่าเรามีความซับซ้อนมากกว่าสถานการณ์เริ่มต้นเหล่านี้และได้ตัดสินใจว่าอัตราตัวอย่าง 10% นั้นเป็นอัตราขั้นต่ำที่จะทำให้เราได้รับแผนการที่เราต้องการในขณะที่รักษาเวลาให้อยู่ในกรอบเวลาที่เหมาะสม
- อัพเดตสถิติที่ไม่เพิ่มขึ้นด้วยตัวอย่าง 10 เปอร์เซ็นต์: เวลา CPU = 2344 ms, เวลาที่ผ่านไป = 2441 มิลลิวินาที
- อัปเดตสถิติส่วนเพิ่มพร้อมตัวอย่าง 10 เปอร์เซ็นต์: เวลา CPU = 2344 ms, เวลาที่ผ่านไป = 2388 มิลลิวินาที
จนถึงตอนนี้ยังไม่มีประโยชน์ชัดเจนในการมีสถิติที่เพิ่มขึ้น อย่างไรก็ตามหากเราใช้ประโยชน์จากDMV ที่ไม่มีเอกสาร sys.dm_db_stats_properties_internal()
(ด้านล่าง) คุณสามารถรับข้อมูลเชิงลึกเกี่ยวกับพาร์ติชันที่คุณอาจต้องการอัปเดต สมมติว่าเราทำการเปลี่ยนแปลงข้อมูลในพาร์ติชัน 3 และเราต้องการให้สถิติมีความสดใหม่สำหรับการค้นหาที่เข้ามา ตัวเลือกของเรามีดังนี้:
- อัปเดตแบบไม่เพิ่มที่ค่าเริ่มต้น (รวมถึงพฤติกรรมเริ่มต้นของการอัปเดตสถิติอัตโนมัติ): 408 ms
- อัปเดตไม่เพิ่มที่ 10%: 2441 ms
- อัปเดตสถิติเพิ่มเติมส่วนที่ 3 ด้วย Resample (10% - อัตราตัวอย่างของเราที่กำหนด): เวลา CPU = 63 ms, เวลาที่ผ่านไป = 63 ms
ที่นี่เราจำเป็นต้องตัดสินใจ เราจะชนะด้วย 63 มิลลิวินาที การอัพเดทสถิติตามพาร์ติชั่นหรือเราชนอัตราตัวอย่างสูงกว่านี้ไหม? สมมติว่าเรายินดีที่จะเริ่มต้นการสุ่มตัวอย่างที่ 50% ตามสถิติที่เพิ่มขึ้น:
- อัปเดตสถิติเพิ่มเติมแบบ 50%: เวลาที่ผ่านไป = 16840 มิลลิวินาที
- อัปเดตสถิติเพิ่มเติมส่วนที่ 3 พร้อม Resample (50% - เวลาอัปเดตใหม่ของเรา): เวลาที่ผ่านไป = 295 ms
เราสามารถสุ่มตัวอย่างข้อมูลได้มากขึ้นอาจตั้งค่าเครื่องมือเพิ่มประสิทธิภาพเพื่อคาดเดาข้อมูลของเราได้ดีขึ้น (แม้ว่าจะยังไม่ได้ใช้สถิติระดับพาร์ติชัน แต่) และเราสามารถทำสิ่งนี้ได้เร็วกว่าที่เรามี สถิติที่เพิ่มขึ้น
สิ่งหนึ่งที่สนุกที่จะคิดออก การอัพเดตสถิติแบบซิงโครนัสคืออะไร? อัตราตัวอย่าง 50% ถูกเก็บรักษาไว้หรือไม่แม้ว่าจะมีการป้อนอัตโนมัติหรือไม่
ฉันลบข้อมูลจากพาร์ติชัน 3 และเรียกใช้คิวรีบน CreationDate และตรวจสอบแล้วตรวจสอบอัตราด้วยคิวรีเดียวกันด้านล่าง อัตราตัวอย่าง 50% ถูกรักษาไว้
เรื่องสั้นที่มีความยาว: สถิติที่เพิ่มขึ้นอาจเป็นเครื่องมือที่มีประโยชน์โดยมีปริมาณความคิดและการตั้งค่าเริ่มต้นที่เหมาะสม อย่างไรก็ตามคุณต้องทราบปัญหาที่คุณพยายามแก้ไขแล้วคุณต้องแก้ไขให้เหมาะสม หากคุณได้รับการประเมินความสำคัญเชิงหัวใจที่ไม่ดีคุณอาจจะได้รับแผนการที่ดีขึ้นด้วยอัตราตัวอย่างเชิงกลยุทธ์และการแทรกแซงการลงทุน อย่างไรก็ตามคุณจะได้รับผลประโยชน์เพียงเล็กน้อยเนื่องจากการใช้ฮิสโตแกรมนั้นเป็นหน้าสถิติที่รวมเข้าด้วยกันและไม่ใช่ข้อมูลระดับพาร์ติชัน หากคุณรู้สึกเจ็บปวดในหน้าต่างการบำรุงรักษาสถิติที่เพิ่มขึ้นอาจช่วยคุณได้ แต่มันอาจจะทำให้คุณต้องตั้งค่ากระบวนการแทรกแซงการบำรุงรักษาแบบสัมผัสสูง โดยไม่คำนึงถึง:
- สถิติที่สร้างด้วยดัชนีที่ไม่ได้จัดพาร์ติชันไว้กับตารางฐาน
- สถิติที่สร้างขึ้นบนฐานข้อมูลรองที่สามารถอ่านได้ AlwaysOn
- สถิติที่สร้างบนฐานข้อมูลแบบอ่านอย่างเดียว
- สถิติที่สร้างขึ้นบนดัชนีที่กรองแล้ว
- สถิติที่สร้างขึ้นในมุมมอง
- สถิติที่สร้างขึ้นในตารางภายใน
- สถิติที่สร้างด้วยดัชนีเชิงพื้นที่หรือดัชนี XML
หวังว่านี่จะช่วยได้
select
sysdatetime(),
schema_name = sh.name,
table_name = t.name,
stat_name = s.name,
index_name = i.name,
leading_column = index_col(quotename(sh.name)+'.'+quotename(t.name),s.stats_id,1),
s.stats_id,
parition_number = isnull(sp.partition_number,1),
s.has_filter,
s.is_incremental,
s.auto_created,
sp.last_updated,
sp.rows,
sp.rows_sampled,
sp.unfiltered_rows,
modification_counter = coalesce(sp.modification_counter, n1.modification_counter)
from sys.stats s
join sys.tables t
on s.object_id = t.object_id
join sys.schemas sh
on t.schema_id = sh.schema_id
left join sys.indexes i
on s.object_id = i.object_id
and s.name = i.name
cross apply sys.dm_db_stats_properties_internal(s.object_id, s.stats_id) sp
outer apply sys.dm_db_stats_properties_internal(s.object_id, s.stats_id) n1
where n1.node_id = 1
and (
(is_incremental = 0)
or
(is_incremental = 1 and sp.partition_number is not null)
)
and t.name = 'Posts'
and s.name like 'st_posts%'
order by s.stats_id,isnull(sp.partition_number,1)