การประเมินภาวะเชิงหัวใจนอกฮิสโตแกรม


14

ติดตั้ง

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

  • เวอร์ชัน 2010 ของฐานข้อมูล Stack Overflow
  • SQL Server 2017 CU15 + GDR (KB4505225) - 14.0.3192.2
  • CE ใหม่ (ระดับความเข้ากันได้ 140)

ฉันมี proc นี้:

USE StackOverflow2010;
GO

CREATE OR ALTER PROCEDURE #sp_PostsByCommentCount
    @CommentCount int
AS
BEGIN
    SELECT * 
    FROM dbo.Posts p
    WHERE 
        p.CommentCount = @CommentCount
    OPTION (RECOMPILE); 
END;
GO

ไม่มีดัชนีหรือสถิติที่ไม่ใช่คลัสเตอร์ในdbo.Postsตาราง (มีดัชนีคลัสเตอร์บนId)

เมื่อถามแผนโดยประมาณสำหรับสิ่งนี้ "แถวโดยประมาณ" ที่ออกมาdbo.Postsคือ 1,934.99:

EXEC #sp_PostsByCommentCount @CommentCount = 51;

วัตถุสถิติต่อไปนี้ถูกสร้างขึ้นโดยอัตโนมัติเมื่อฉันถามแผนโดยประมาณ:

DBCC SHOW_STATISTICS('dbo.Posts', [_WA_Sys_00000006_0519C6AF]);

สกรีนช็อตของเอาต์พุตสถิติใน SSMS

ไฮไลท์จากที่:

  • สถิติมีอัตราตัวอย่างค่อนข้างต่ำ 1.81% (67,796 / 3,744,192)
  • ใช้ขั้นตอนฮิสโตแกรมเพียง 31 ขั้นเท่านั้น
  • ค่า "ความหนาแน่นทั้งหมด" คือ0.03030303(สุ่มตัวอย่างค่า 33 ค่า)
  • RANGE_HI_KEYฮิสโตแกรมสุดท้ายคือ 50 โดยมีEQ_ROWS1

คำถาม

การส่งค่าใด ๆ ที่สูงกว่า 50 (ขึ้นไปและรวม 2,147,483,647) จะทำให้มีการประมาณการแถว 1,934.99 การคำนวณหรือมูลค่าใดที่ใช้ในการสร้างการประมาณนี้ ตัวประมาณค่า cardinality ดั้งเดิมสร้างการประมาณ 1 แถวโดยวิธีการ

สิ่งที่ฉันได้ลอง

นี่คือทฤษฎีบางอย่างที่ฉันมีสิ่งที่ฉันพยายามหรือข้อมูลเพิ่มเติมที่ฉันสามารถขุดขึ้นมาในขณะที่มองสิ่งนี้

เวกเตอร์ความหนาแน่น

ตอนแรกฉันคิดว่ามันจะเป็นเวกเตอร์ความหนาแน่นเหมือนกับที่ฉันใช้ OPTION (OPTIMIZE FOR UNKNOWN)ผมเริ่มคิดว่ามันจะเวกเตอร์ความหนาแน่นเช่นเดียวกับถ้าผมใช้แต่เวกเตอร์ความหนาแน่นสำหรับวัตถุสถิตินี้คือ 3,744,192 * 0.03030303 = 113,460 ดังนั้นนั่นไม่ใช่

เหตุการณ์เพิ่มเติม

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

<CalculatorList>
  <FilterCalculator CalculatorName="CSelCalcColumnInInterval" Selectivity="-1.000" 
                    CalculatorFailed="true" TableName="[p]" ColumnName="CommentCount" />

  <FilterCalculator CalculatorName="CSelCalcAscendingKeyFilter" Selectivity="0.001" 
                    TableName="[p]" ColumnName="CommentCount" UseAverageFrequency="true" 
                    StatId="4" />
</CalculatorList>

ดังนั้นจึงปรากฏว่าCSelCalcAscendingKeyFilterมีการใช้เครื่องคิดเลข (อีกเครื่องหนึ่งบอกว่ามันล้มเหลวไม่ว่าจะเป็นอะไรก็ตาม) คอลัมน์นี้ไม่ใช่กุญแจสำคัญหรือมีเอกลักษณ์หรือจำเป็นต้องขึ้นไป แต่อย่างใด

การทำ Googling ของคำนั้นทำให้ฉันไปที่โพสต์บล็อกบางส่วน:

การโพสต์เหล่านี้บ่งชี้ว่า CE ใหม่ใช้การประมาณนอกกราฟเหล่านี้ในการรวมกันของเวกเตอร์ความหนาแน่นและตัวนับการปรับเปลี่ยนของสถิติ แต่น่าเสียดายที่ฉันได้ตัดเวกเตอร์ความหนาแน่น (ฉันคิดว่า?!) และตัวนับการแก้ไขเป็นศูนย์ (ต่อsys.dm_db_stats_propertiesไป)

ติดตามสถานะ

Forrestแนะนำให้ฉันเปิด TF 2363 เพื่อรับข้อมูลเพิ่มเติมเกี่ยวกับกระบวนการประมาณ ฉันคิดว่าสิ่งที่เกี่ยวข้องที่สุดจากผลลัพธ์นั้นคือ:

Plan for computation:

  CSelCalcAscendingKeyFilter(avg. freq., QCOL: [p].CommentCount)

Selectivity: 0.000516798

นี่คือความก้าวหน้า (ขอบคุณ Forrest!): 0.000516798หมายเลขนั้น(ซึ่งดูเหมือนว่าจะถูกปัดเศษโดยไม่มีประโยชน์ในSelectivity="0.001"แอตทริบิวต์XE ด้านบน) คูณด้วยจำนวนแถวในตารางคือค่าประมาณที่ฉันได้ค้นหา (1,934.99)

ฉันอาจจะขาดอะไรบางอย่างที่เห็นได้ชัด แต่ฉันไม่สามารถย้อนกลับวิศวกรรมได้ว่าค่าการเลือกเกิดขึ้นในCSelCalcAscendingKeyFilterเครื่องคิดเลขอย่างไร

คำตอบ:


13

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

ในกรณีของคุณ 1,934.99 = SQRT (3744192)

การตั้งค่าการทดสอบด้านล่าง:

--setup
USE TestDB
ALTER DATABASE [TestDB] SET AUTO_UPDATE_STATISTICS OFF
GO

DROP TABLE IF EXISTS dbo.Hist

CREATE TABLE dbo.Hist (
ID int identity primary key,
Num int
)

INSERT dbo.Hist
SELECT TOP 300
(ROW_NUMBER() OVER(ORDER BY(SELECT 1/0)))%3
FROM master..spt_values a
CROSS JOIN master..spt_values b
--Get estimated plan
--don't forget to run right after setup to auto-create stats
SELECT *
FROM dbo.Hist
WHERE Num = 1000
--gradually add rows, then rerun estimate above
INSERT dbo.Hist
SELECT TOP 100
-1
FROM master..spt_values a
--I sure hope you weren't testing this in prod (cleanup)
ALTER DATABASE [TestDB] SET AUTO_UPDATE_STATISTICS ON
GO

น่าประหลาดใจที่การประมาณแถวถูกสร้างขึ้นจากวิธีนี้: 20 ที่ 400 แถวทั้งหมด, 30 ที่ 900, 40 ที่ 1600, ฯลฯ

10,000 ที่ผ่านมาแม้ว่าแถวประมาณค่าสูงสุดที่ 100 ซึ่งเป็นจำนวนแถวต่อมูลค่าในสถิติที่มีอยู่ การเพิ่มเพียง 10 แถวจะตั้งค่าการประมาณเป็น 10 เนื่องจาก sqrt (300)> 10

ดังนั้นการประมาณสามารถแสดงโดยใช้สูตรนี้:

Estimate = MIN(SQRT(AC), MIN(AR, MC))

โปรดทราบว่าหากสถิติถูกสุ่มตัวอย่างแล้ว MC จะไม่ถูกนำมาพิจารณา ดังนั้นสูตรจึงกลายเป็น:

Estimate = MIN(SQRT(AC), AR))

ที่ไหน

  • MC คือ "การแก้ไขนับ" (จำนวนการแก้ไขนับตั้งแต่สร้างสถิติ)
  • AC คือ "cardinality ที่ปรับแล้ว" (# ของแถวจากสถิติรวมถึง MC)
  • AR คือแถวเฉลี่ยต่อมูลค่า (# ของแถวจากสถิติหารด้วยค่าที่แตกต่างในคอลัมน์)

สูตรสำหรับการประมาณเหล่านี้และรายละเอียดอื่น ๆ เกี่ยวกับเครื่องคิดเลขสามารถพบได้ในบล็อกโพสต์นี้: การวิเคราะห์การประเมินจาก CSelCalcAscendingKeyFilter Calculator

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