จำนวนขั้นตอนฮิสโตแกรมมีการตัดสินใจในสถิติอย่างไร


11

จำนวนขั้นตอนฮิสโตแกรมมีการตัดสินใจในสถิติใน SQL Server อย่างไร

ทำไมถึง จำกัด เพียง 200 ขั้นตอนถึงแม้ว่าคอลัมน์หลักของฉันมีค่าแตกต่างกันมากกว่า 200 ค่า มีปัจจัยในการตัดสินใจหรือไม่?


การสาธิต

นิยามสคีมา

CREATE TABLE histogram_step
  (
     id   INT IDENTITY(1, 1),
     name VARCHAR(50),
     CONSTRAINT pk_histogram_step PRIMARY KEY (id)
  )

การแทรก 100 บันทึกลงในตารางของฉัน

INSERT INTO histogram_step
            (name)
SELECT TOP 100 name
FROM   sys.syscolumns

การอัปเดตและตรวจสอบสถิติ

UPDATE STATISTICS histogram_step WITH fullscan

DBCC show_statistics('histogram_step', pk_histogram_step)

ขั้นตอนฮิสโตแกรม:

+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
|            1 |          0 |       1 |                   0 |              1 |
|            3 |          1 |       1 |                   1 |              1 |
|            5 |          1 |       1 |                   1 |              1 |
|            7 |          1 |       1 |                   1 |              1 |
|            9 |          1 |       1 |                   1 |              1 |
|           11 |          1 |       1 |                   1 |              1 |
|           13 |          1 |       1 |                   1 |              1 |
|           15 |          1 |       1 |                   1 |              1 |
|           17 |          1 |       1 |                   1 |              1 |
|           19 |          1 |       1 |                   1 |              1 |
|           21 |          1 |       1 |                   1 |              1 |
|           23 |          1 |       1 |                   1 |              1 |
|           25 |          1 |       1 |                   1 |              1 |
|           27 |          1 |       1 |                   1 |              1 |
|           29 |          1 |       1 |                   1 |              1 |
|           31 |          1 |       1 |                   1 |              1 |
|           33 |          1 |       1 |                   1 |              1 |
|           35 |          1 |       1 |                   1 |              1 |
|           37 |          1 |       1 |                   1 |              1 |
|           39 |          1 |       1 |                   1 |              1 |
|           41 |          1 |       1 |                   1 |              1 |
|           43 |          1 |       1 |                   1 |              1 |
|           45 |          1 |       1 |                   1 |              1 |
|           47 |          1 |       1 |                   1 |              1 |
|           49 |          1 |       1 |                   1 |              1 |
|           51 |          1 |       1 |                   1 |              1 |
|           53 |          1 |       1 |                   1 |              1 |
|           55 |          1 |       1 |                   1 |              1 |
|           57 |          1 |       1 |                   1 |              1 |
|           59 |          1 |       1 |                   1 |              1 |
|           61 |          1 |       1 |                   1 |              1 |
|           63 |          1 |       1 |                   1 |              1 |
|           65 |          1 |       1 |                   1 |              1 |
|           67 |          1 |       1 |                   1 |              1 |
|           69 |          1 |       1 |                   1 |              1 |
|           71 |          1 |       1 |                   1 |              1 |
|           73 |          1 |       1 |                   1 |              1 |
|           75 |          1 |       1 |                   1 |              1 |
|           77 |          1 |       1 |                   1 |              1 |
|           79 |          1 |       1 |                   1 |              1 |
|           81 |          1 |       1 |                   1 |              1 |
|           83 |          1 |       1 |                   1 |              1 |
|           85 |          1 |       1 |                   1 |              1 |
|           87 |          1 |       1 |                   1 |              1 |
|           89 |          1 |       1 |                   1 |              1 |
|           91 |          1 |       1 |                   1 |              1 |
|           93 |          1 |       1 |                   1 |              1 |
|           95 |          1 |       1 |                   1 |              1 |
|           97 |          1 |       1 |                   1 |              1 |
|           99 |          1 |       1 |                   1 |              1 |
|          100 |          0 |       1 |                   0 |              1 |
+--------------+------------+---------+---------------------+----------------+

อย่างที่เราเห็นมี 53 ขั้นตอนในฮิสโตแกรม

แทรกอีกสองสามพันระเบียน

INSERT INTO histogram_step
            (name)
SELECT TOP 10000 b.name
FROM   sys.syscolumns a
       CROSS JOIN sys.syscolumns b

การอัปเดตและตรวจสอบสถิติ

UPDATE STATISTICS histogram_step WITH fullscan

DBCC show_statistics('histogram_step', pk_histogram_step)

ตอนนี้ขั้นตอนฮิสโตแกรมจะลดลงเป็น 4 ขั้นตอน

+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
|            1 |          0 |       1 |                   0 |              1 |
|        10088 |      10086 |       1 |               10086 |              1 |
|        10099 |         10 |       1 |                  10 |              1 |
|        10100 |          0 |       1 |                   0 |              1 |
+--------------+------------+---------+---------------------+----------------+

แทรกอีกสองสามพันระเบียน

INSERT INTO histogram_step
            (name)
SELECT TOP 100000 b.name
FROM   sys.syscolumns a
       CROSS JOIN sys.syscolumns b

การอัปเดตและตรวจสอบสถิติ

UPDATE STATISTICS histogram_step WITH fullscan

DBCC show_statistics('histogram_step', pk_histogram_step) 

ตอนนี้ขั้นตอนฮิสโตแกรมจะลดลงเป็น 3 ขั้นตอน

+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
|            1 |          0 |       1 |                   0 |              1 |
|       110099 |     110097 |       1 |              110097 |              1 |
|       110100 |          0 |       1 |                   0 |              1 |
+--------------+------------+---------+---------------------+----------------+

มีใครบอกฉันได้ว่าขั้นตอนเหล่านี้ถูกตัดสินแล้วอย่างไร


3
200 เป็นตัวเลือกโดยพลการ ไม่มีอะไรเกี่ยวข้องกับจำนวนค่าที่แตกต่างที่คุณมีในตารางที่ระบุ ถ้าคุณต้องการรู้ว่าทำไมเลือก 200 ตัวคุณจะต้องถามวิศวกรจากทีมงาน SQL Server ในปี 1990 ไม่ใช่เพื่อนร่วมงานของคุณ
Aaron Bertrand

1
@AaronBertrand - ขอบคุณ .. ดังนั้นขั้นตอนเหล่านี้จึงตัดสินใจได้อย่างไร
P ரதீப்

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

1
ฉันได้ถามคำถามที่คล้ายกันเกี่ยวกับการประมาณค่าอินทราสเตปอาจมีประโยชน์กับdba.stackexchange.com/questions/148523/ …
jesijesi

คำตอบ:


14

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

เมื่อ SQL Server พิจารณาว่าจำเป็นต้องมีการอัปเดตสถิติมันจะเริ่มต้นการสืบค้นที่ซ่อนอยู่ซึ่งจะอ่านข้อมูลทั้งหมดของตารางหรือตัวอย่างของข้อมูลของตาราง คุณสามารถดูข้อความค้นหาเหล่านี้ด้วยเหตุการณ์ที่ขยาย มีฟังก์ชั่นที่เรียกว่าStatManภายใน SQL Server ที่เกี่ยวข้องกับการสร้างฮิสโตแกรม สำหรับวัตถุทางสถิติอย่างง่ายมีStatManเคียวรีอย่างน้อยสองชนิดที่ต่างกัน(มีเคียวรีที่แตกต่างกันสำหรับการอัพเดตสถิติด่วนและฉันสงสัยว่าคุณลักษณะสถิติส่วนเพิ่มบนตารางที่แบ่งพาร์ติชันก็ใช้แบบสอบถามที่ต่างกันด้วย)

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

CREATE TABLE X_SHOW_ME_STATMAN (N INT);
CREATE STATISTICS X_STAT_X_SHOW_ME_STATMAN ON X_SHOW_ME_STATMAN (N);

-- after gathering stats with 1 row in table
SELECT StatMan([SC0]) FROM
(
    SELECT TOP 100 PERCENT [N] AS [SC0] 
    FROM [dbo].[X_SHOW_ME_STATMAN] WITH (READUNCOMMITTED)
    ORDER BY [SC0] 
) AS _MS_UPDSTATS_TBL 
OPTION (MAXDOP 16);

SQL Server เลือกขนาดตัวอย่างอัตโนมัติตามขนาดของตาราง (ฉันคิดว่าเป็นทั้งจำนวนแถวและหน้าในตาราง) หากตารางมีขนาดใหญ่เกินไปขนาดตัวอย่างอัตโนมัติจะต่ำกว่า 100% นี่คือสิ่งที่ฉันได้รับสำหรับตารางเดียวกันที่มี 1 ล้านแถว:

-- after gathering stats with 1 M rows in table
SELECT StatMan([SC0], [SB0000]) FROM 
(
    SELECT TOP 100 PERCENT [SC0], step_direction([SC0]) over (order by NULL) AS [SB0000] 
    FROM 
    (
        SELECT [N] AS [SC0] 
        FROM [dbo].[X_SHOW_ME_STATMAN] TABLESAMPLE SYSTEM (6.666667e+001 PERCENT) WITH (READUNCOMMITTED) 
    ) AS _MS_UPDSTATS_TBL_HELPER 
    ORDER BY [SC0], [SB0000] 
) AS _MS_UPDSTATS_TBL
OPTION (MAXDOP 1);

TABLESAMPLEได้รับการบันทึกไว้แต่ StatMan และ step_direction ไม่ใช่ นี่คือตัวอย่าง SQL Server ประมาณ 66.6% ของข้อมูลจากตารางเพื่อสร้างฮิสโตแกรม สิ่งนี้หมายความว่าคุณจะได้รับจำนวนฮิสโตแกรมที่แตกต่างกันเมื่ออัปเดตสถิติ (ไม่รวมFULLSCAN) ในข้อมูลเดียวกัน ฉันไม่เคยสังเกตเรื่องนี้ในทางปฏิบัติ แต่ฉันไม่เห็นว่าทำไมมันเป็นไปไม่ได้

ลองทำการทดสอบสองสามอย่างกับข้อมูลง่าย ๆ เพื่อดูว่าสถิติเปลี่ยนแปลงไปตามเวลาอย่างไร ด้านล่างคือรหัสทดสอบที่ฉันเขียนเพื่อแทรกจำนวนเต็มตามลำดับลงในตารางรวบรวมสถิติหลังการแทรกแต่ละครั้งและบันทึกข้อมูลเกี่ยวกับสถิติลงในตารางผลลัพธ์ เริ่มต้นด้วยการแทรกเพียง 1 แถวต่อครั้งมากถึง 10,000 เตียงทดสอบ:

DECLARE
@stats_id INT,
@table_object_id INT,
@rows_per_loop INT = 1,
@num_of_loops INT = 10000,
@loop_num INT;

BEGIN
    SET NOCOUNT ON;

    TRUNCATE TABLE X_STATS_RESULTS;

    SET @table_object_id = OBJECT_ID ('X_SEQ_NUM');
    SELECT @stats_id = stats_id FROM sys.stats
    WHERE OBJECT_ID = @table_object_id
    AND name = 'X_STATS_SEQ_INT_FULL';

    SET @loop_num = 0;
    WHILE @loop_num < @num_of_loops
    BEGIN
        SET @loop_num = @loop_num + 1;

        INSERT INTO X_SEQ_NUM WITH (TABLOCK)
        SELECT @rows_per_loop * (@loop_num - 1) + N FROM dbo.GetNums(@rows_per_loop);

        UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN; -- can comment out FULLSCAN as needed

        INSERT INTO X_STATS_RESULTS WITH (TABLOCK)
        SELECT 'X_STATS_SEQ_INT_FULL', @rows_per_loop * @loop_num, rows_sampled, steps 
        FROM sys.dm_db_stats_properties(@table_object_id, @stats_id);
        END;
END;

สำหรับข้อมูลนี้จำนวนขั้นตอนฮิสโตแกรมจะเพิ่มขึ้นอย่างรวดเร็วเป็น 200 (ครั้งแรกจะไปถึงจำนวนสูงสุดของขั้นตอนที่มี 397 แถว) อยู่ที่ 199 หรือ 200 จนกระทั่งแถว 1485 อยู่ในตารางจากนั้นค่อย ๆ ลดลงจนกระทั่งฮิสโตแกรมมีเพียง 3 หรือ 4 ขั้นตอน นี่คือกราฟของข้อมูลทั้งหมด:

กราฟแรก

นี่คือฮิสโตแกรมที่ดูเหมือนกับแถว 10k:

RANGE_HI_KEY    RANGE_ROWS  EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS
1               0           1       0                   1
9999            9997        1       9997                1
10000           0           1       0                   1

มันเป็นปัญหาที่ฮิสโตแกรมมีเพียง 3 ขั้นตอนหรือไม่? ดูเหมือนว่าข้อมูลจะถูกเก็บรักษาไว้จากมุมมองของเรา โปรดทราบว่าเนื่องจากประเภทข้อมูลนั้นเป็นจำนวนเต็มเราจึงสามารถหาจำนวนแถวในตารางสำหรับแต่ละจำนวนเต็มตั้งแต่ 1 ถึง 10,000 โดยปกติแล้ว SQL Server สามารถคำนวณได้เช่นกันถึงแม้ว่าจะมีบางกรณีที่ค่อนข้างไม่ได้ผล . ดูโพสต์ SE นี้สำหรับตัวอย่างของสิ่งนี้

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

DELETE FROM X_SEQ_NUM
WHERE X_NUM  = 1000;

UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN;

DBCC SHOW_STATISTICS ('X_SEQ_NUM', 'X_STATS_SEQ_INT_FULL'); -- still 3 steps

DELETE FROM X_SEQ_NUM
WHERE X_NUM  IN (2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000);

UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN;

DBCC SHOW_STATISTICS ('X_SEQ_NUM', 'X_STATS_SEQ_INT_FULL'); -- still 3 steps

มันน่าผิดหวังเล็กน้อย ถ้าเราสร้างฮิสโตแกรมด้วยมือเราจะเพิ่มขั้นตอนสำหรับค่าที่ขาดหายไปแต่ละอัน SQL Server ใช้อัลกอริทึมสำหรับวัตถุประสงค์ทั่วไปดังนั้นสำหรับชุดข้อมูลบางชุดเราอาจสามารถสร้างฮิสโตแกรมที่เหมาะสมกว่ารหัสที่ใช้ แน่นอนความแตกต่างระหว่างการรับ 0 หรือ 1 แถวจากตารางมีขนาดเล็กมาก ฉันได้ผลลัพธ์เดียวกันเมื่อทดสอบด้วย 20,000 แถวซึ่งแต่ละจำนวนเต็มมี 2 แถวในตาราง ฮิสโตแกรมไม่ได้รับขั้นตอนเมื่อฉันลบข้อมูล

RANGE_HI_KEY    RANGE_ROWS  EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS
1               0           2       0                   1
9999            19994       2       9997                2
10000           0           2       0                   1

ถ้าฉันทดสอบกับ 1 ล้านแถวโดยที่แต่ละจำนวนเต็มมี 100 แถวในตารางฉันจะได้ผลลัพธ์ที่ดีขึ้นเล็กน้อย แต่ฉันยังสามารถสร้างฮิสโตแกรมที่ดีขึ้นได้ด้วยมือ

truncate table X_SEQ_NUM;

BEGIN TRANSACTION;
INSERT INTO X_SEQ_NUM WITH (TABLOCK)
SELECT N FROM dbo.GetNums(10000);
GO 100
COMMIT TRANSACTION;

UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN;

DBCC SHOW_STATISTICS ('X_SEQ_NUM', 'X_STATS_SEQ_INT_FULL'); -- 4 steps

DELETE FROM X_SEQ_NUM
WHERE X_NUM  = 1000;

UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN;

DBCC SHOW_STATISTICS ('X_SEQ_NUM', 'X_STATS_SEQ_INT_FULL'); -- now 5 steps with a RANGE_HI_KEY of 998 (?)

DELETE FROM X_SEQ_NUM
WHERE X_NUM  IN (2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000);

UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN;

DBCC SHOW_STATISTICS ('X_SEQ_NUM', 'X_STATS_SEQ_INT_FULL'); -- still 5 steps

ฮิสโตแกรมสุดท้าย:

RANGE_HI_KEY    RANGE_ROWS  EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS
1               0           100     0                   1
998             99600       100     996                 100
3983            298100      100     2981                100
9999            600900      100     6009                100
10000           0           100     0                   1

ลองทดสอบเพิ่มเติมด้วยจำนวนเต็มตามลำดับ แต่มีแถวเพิ่มเติมในตาราง โปรดทราบว่าสำหรับตารางที่มีขนาดเล็กเกินไปที่ระบุขนาดตัวอย่างด้วยตนเองจะไม่มีผลดังนั้นฉันจะเพิ่ม 100 แถวในแต่ละส่วนแทรกและรวบรวมสถิติในแต่ละครั้งมากถึง 1 ล้านแถว ฉันเห็นรูปแบบที่คล้ายกันเหมือนก่อนยกเว้นเมื่อฉันไปถึง 637300 แถวในตารางฉันจะไม่สุ่มตัวอย่าง 100% ของแถวในตารางอีกต่อไปด้วยอัตราตัวอย่างเริ่มต้น เมื่อฉันเพิ่มแถวจำนวนฮิสโตแกรมจะเพิ่มขึ้น บางทีนี่อาจเป็นเพราะ SQL Server จบลงด้วยช่องว่างในข้อมูลที่มากขึ้นเนื่องจากจำนวนแถวที่ไม่ได้เก็บตัวอย่างในตารางเพิ่มขึ้น ฉันไม่ตี 200 ขั้นแม้ที่ 1 M แถว แต่ถ้าฉันเพิ่มแถวต่อไปฉันคาดว่าฉันจะไปที่นั่นและในที่สุดก็เริ่มกลับลงมา

กราฟ 2

แกน X คือจำนวนแถวในตาราง เมื่อจำนวนแถวเพิ่มขึ้นแถวตัวอย่างจะแตกต่างกันเล็กน้อยและไม่เกิน 650k

ทีนี้ลองทำการทดสอบง่ายๆกับข้อมูล VARCHAR

CREATE TABLE X_SEQ_STR (X_STR VARCHAR(5));
CREATE STATISTICS X_SEQ_STR ON X_SEQ_STR(X_STR);

ที่นี่ฉันใส่ 200 หมายเลข (เป็นสตริง) พร้อมกับ NULL

INSERT INTO X_SEQ_STR
SELECT N FROM dbo.GetNums(200)
UNION ALL
SELECT NULL;

UPDATE STATISTICS X_SEQ_STR X_SEQ_STR ;

DBCC SHOW_STATISTICS ('X_SEQ_STR', 'X_SEQ_STR'); -- 111 steps, RANGE_ROWS is 0 or 1 for all steps

โปรดทราบว่า NULL ได้รับขั้นตอนฮิสโตแกรมของตัวเองเสมอเมื่อพบในตาราง SQL Server อาจให้ขั้นตอนทั้งหมด 201 ขั้นตอนแก่ฉันในการเก็บรักษาข้อมูลทั้งหมด แต่ไม่ได้ทำเช่นนั้น ข้อมูลทางเทคนิคหายไปเนื่องจาก '1111' เรียงลำดับระหว่าง '1' และ '2'

ตอนนี้ลองแทรกอักขระที่แตกต่างกันแทนที่จะเป็นจำนวนเต็มเพียง:

truncate table X_SEQ_STR;

INSERT INTO X_SEQ_STR
SELECT CHAR(10 + N) FROM dbo.GetNums(200)
UNION ALL
SELECT NULL;

UPDATE STATISTICS X_SEQ_STR X_SEQ_STR ;

DBCC SHOW_STATISTICS ('X_SEQ_STR', 'X_SEQ_STR'); -- 95 steps, RANGE_ROWS is 0 or 1 or 2

ไม่แตกต่างจากการทดสอบครั้งสุดท้าย

ตอนนี้เราลองแทรกตัวอักษร แต่ใส่ตัวเลขที่แตกต่างกันของตัวละครแต่ละตัวลงในตาราง ตัวอย่างเช่นCHAR(11)มี 1 แถวCHAR(12)มี 2 ​​แถว ฯลฯ

truncate table X_SEQ_STR;

DECLARE
@loop_num INT;

BEGIN
    SET NOCOUNT ON;

    SET @loop_num = 0;
    WHILE @loop_num < 200
    BEGIN
        SET @loop_num = @loop_num + 1;

        INSERT INTO X_SEQ_STR WITH (TABLOCK)
        SELECT CHAR(10 + @loop_num) FROM dbo.GetNums(@loop_num);
    END;
END;

UPDATE STATISTICS X_SEQ_STR X_SEQ_STR ;

DBCC SHOW_STATISTICS ('X_SEQ_STR', 'X_SEQ_STR'); -- 148 steps, most with RANGE_ROWS of 0

ก่อนหน้านี้ฉันยังไม่ได้รับ 200 ขั้นตอนฮิสโตแกรมอย่างแน่นอน อย่างไรก็ตามหลายขั้นตอนมีRANGE_ROWS0

สำหรับการทดสอบครั้งสุดท้ายฉันจะแทรกสตริงแบบสุ่ม 5 ตัวอักษรในแต่ละวงและรวบรวมสถิติในแต่ละครั้ง นี่คือรหัสสตริงสุ่ม:

char((rand()*25 + 65))+char((rand()*25 + 65))+char((rand()*25 + 65))+char((rand()*25 + 65))+char((rand()*25 + 65))

นี่คือกราฟของแถวในตารางเทียบกับขั้นตอนฮิสโตแกรม: กราฟ 3

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

ROWS_IN_TABLE   ROWS_SAMPLED    STEPS
36661           36661           133
36662           36662           143
36663           36663           143
36664           36664           141
36665           36665           138

แม้ว่าการสุ่มตัวอย่างด้วยFULLSCANการเพิ่มแถวเดียวสามารถเพิ่มจำนวนขั้นตอนที่ 10 ให้คงที่แล้วลดลง 2 จากนั้นลดลง 3

เราสรุปอะไรจากทั้งหมดนี้ได้บ้าง? ฉันไม่สามารถพิสูจน์สิ่งนี้ได้ แต่การสังเกตเหล่านี้ดูเหมือนจะเป็นจริง:

  • SQL Server ใช้อัลกอริทึมการใช้งานทั่วไปเพื่อสร้างฮิสโตแกรม สำหรับการแจกแจงข้อมูลบางอย่างอาจเป็นไปได้ที่จะสร้างการแสดงข้อมูลที่สมบูรณ์ยิ่งขึ้นด้วยมือ
  • หากมีข้อมูล NULL ในตารางและแบบสอบถามสถิติพบว่าข้อมูล NULL นั้นจะได้รับขั้นตอนฮิสโตแกรมของตัวเองเสมอ
  • ค่าต่ำสุดที่พบในตารางได้รับขั้นตอนฮิสโตแกรมของตัวเองด้วยRANGE_ROWS= 0
  • ค่าสูงสุดที่พบในตารางจะเป็นค่าสุดท้ายRANGE_HI_KEYในตาราง
  • ในขณะที่ SQL Server ทำการสุ่มตัวอย่างข้อมูลเพิ่มเติมอาจต้องรวมขั้นตอนที่มีอยู่เพื่อให้มีที่ว่างสำหรับข้อมูลใหม่ที่พบ ถ้าคุณดูที่ histograms พอที่คุณอาจจะเห็นซ้ำค่านิยมร่วมกันสำหรับการหรือDISTINCT_RANGE_ROWS RANGE_ROWSตัวอย่างเช่น 255 แสดงจำนวนครั้งRANGE_ROWSและDISTINCT_RANGE_ROWSสำหรับกรณีทดสอบสุดท้ายที่นี่
  • สำหรับการแจกแจงข้อมูลอย่างง่ายคุณอาจเห็น SQL Server รวมข้อมูลตามลำดับเป็นหนึ่งขั้นตอนฮิสโตแกรมที่ทำให้ไม่มีการสูญหายของข้อมูล อย่างไรก็ตามเมื่อเพิ่มช่องว่างลงในข้อมูลฮิสโตแกรมอาจไม่ปรับในแบบที่คุณต้องการ

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

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

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

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

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

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

มีการทดสอบอีกมากมายที่สามารถเรียกใช้ที่นี่ดังนั้นฉันขอแนะนำให้คุณทดสอบ ฉันทำการทดสอบนี้บน SQL Server 2014 โดยด่วนดังนั้นจริงๆไม่มีอะไรหยุดคุณได้


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