ฉันควรปิดการใช้งาน "สถิติการอัพเดทอัตโนมัติ" ในสถานการณ์จำลองคลังข้อมูลหรือไม่


12

ฉันมีคลังข้อมูล 200 GB ใน SQL Server

ฉันประสบกับการดำเนินการช้ามากสำหรับบางข้อความค้นหา ตัวอย่างเช่น 12 ชั่วโมงเพื่อให้ง่ายแบบสอบถามกับdeleteinner join

หลังจากทำการวิจัยด้วยแผนการดำเนินการฉันได้อัปเดตสถิติของตาราง 2 ตารางที่เกี่ยวข้องในแบบสอบถามโดยใช้WITH FULLSCANตัวเลือก

ตอนนี้แบบสอบถามดำเนินการในเวลาน้อยกว่าหนึ่งวินาทีดังนั้นจึงปรากฏว่าสถิติไม่ทันสมัย

ฉันกำลังพิจารณาปิดใช้งานauto update statisticsฐานข้อมูลและทำงานUPDATE STATISTICSด้วยตนเองหลังจากโหลดคลังข้อมูลแล้ว คลังข้อมูลจะถูกโหลดเพิ่มขึ้นจากระบบ ERP ต้นทางทุกวันในเวลากลางคืน

ฉันถูกต้องในการสมมติว่าauto update statisticsในสถานการณ์คลังข้อมูลไม่ได้มีประโยชน์จริง ๆ ? จะเป็นการดีกว่าหรือที่จะอัปเดตสถิติด้วยตนเองหลังจากโหลดข้อมูลแล้ว


นี่เป็นการอ่านที่ดีมากเกี่ยวกับสถิติ: simple-talk.com/sql/performance/ …เรายังทำงานประจำวันโดยใช้โซลูชันของ Ola ola.hallengren.com/ เพื่ออัปเดตสถิติใน 1TB db ฉันจะไม่ปิดใช้งานตัวเลือกสถิติการอัปเดตอัตโนมัติ
Joy Walker

1
ขึ้นอยู่กับจำนวนระเบียนในตารางของคุณและจำนวนที่คุณเพิ่มในชุดงาน ในตารางแถว 1b ที่คุณเพิ่ม 20m แถวต่อคืนสถิติของคุณจะได้รับการอัปเดตทุก ๆ 10 วันซึ่งไม่ดี
JNK

2
เพียงแค่ FYI - มีการตั้งค่าสถานะการติดตาม (2371) เพื่อเปลี่ยนเกณฑ์สำหรับการอัปเดตสถิติจากคงที่ 20% เป็นอัตราเปอร์เซ็นต์แบบไดนามิก ดูเพิ่มเติมได้ที่นี่: blogs.msdn.com/b/saponsqlserver/archive/2011/09/07/ …
DaniSQL

ลิงค์ข้อมูลมากขอบคุณ! @JNK: ใช่มันเป็นฐานข้อมูลขนาดใหญ่ ตาราง staging มี 300m + แถวและขึ้นอยู่กับวันที่เราแทรกบางอย่างระหว่าง 1m ถึง 10m ทุกวัน จะตรวจสอบสถิติให้ละเอียดยิ่งขึ้นตามที่เสนอโดยคำตอบด้านล่าง
saso

คำตอบ:


11

นี่คือเอกสารเมื่อ auto_update สถิติเกิดขึ้น นี่คือจุดสำคัญที่ต้องปรับปรุงสถิติสถิติโดยอัตโนมัติ:

  • ขนาดตารางลดลงจาก 0 ถึง> 0 แถว (ทดสอบ 1)
  • จำนวนแถวในตารางเมื่อรวบรวมสถิติคือ 500 หรือน้อยกว่าและ colmodctr ของคอลัมน์นำของวัตถุสถิติได้เปลี่ยนไปมากกว่า 500 ตั้งแต่นั้นมา (ทดสอบ 2)
  • ตารางมีมากกว่า 500 แถวเมื่อรวบรวมสถิติและ colmodctr ของคอลัมน์นำของวัตถุสถิติมีการเปลี่ยนแปลงมากกว่า 500 + 20% ของจำนวนแถวในตารางเมื่อรวบรวมสถิติ (ทดสอบ 3) .

@JNK ชี้ประเด็นในความคิดเห็นว่าถ้าคุณมี 1 พันล้านแถวในตารางคุณจะต้องมี 20,000,5,000 เขียนไปที่คอลัมน์แรกในสถิติเพื่อเริ่มการอัพเดท

ลองมาดูโครงสร้างต่อไปนี้:

CREATE TABLE dbo.test_table (
    test_table_id INTEGER IDENTITY(1,1) NOT NULL, 
    test_table_value VARCHAR(50), 
    test_table_value2 BIGINT, 
    test_table_value3 NUMERIC(10,2)
);

CREATE CLUSTERED INDEX cix_test_table ON dbo.test_table (test_table_id, test_table_value);

ตอนนี้เราสามารถตรวจสอบเพื่อดูสิ่งที่เกิดขึ้นในสถิติที่ดิน

select * 
    from sys.stats
        where object_id = OBJECT_ID('dbo.test_table')

stat_container

อย่างไรก็ตามเพื่อดูว่านี่เป็นวัตถุทางสถิติที่มีความหมายหรือไม่เราจำเป็นต้อง:

dbcc show_statistics('dbo.test_table',cix_test_table)

histogram

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

    CREATE TABLE test_table (
        test_table_id INTEGER IDENTITY(1,1) NOT NULL, 
        test_table_value VARCHAR(50), 
        test_table_value2 BIGINT, 
        test_table_value3 NUMERIC(10,2)
    );

    CREATE CLUSTERED INDEX cix_test_table ON test_table (test_table_id, test_table_value);

    ALTER TABLE test_table ADD CONSTRAINT pk_test_table PRIMARY KEY  (test_table_id)

    SELECT * 
        FROM sys.stats
            WHERE object_id = OBJECT_ID('dbo.test_table')

    --DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table)
    DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

declare @test int = 0

WHILE @test < 1
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT 'one row|select < 1', * FROM test_table WHERE test_table_id < 1;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

SET @test = 1

WHILE @test < 500
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT '100 rows(add 99)|select < 100',* FROM test_table WHERE test_table_id < 100;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;
--get the table up to 500 rows/changes
WHILE @test < 500
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END
SELECT '500 rows(add 400)|select < 100',* FROM test_table WHERE test_table_id < 100;
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;
SELECT '500 rows(add 400)|select < 500',* FROM test_table WHERE test_table_id < 500;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;
--bump it to 501
SET @test = 500;
WHILE @test < 501
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END


SELECT '501 rows(add 1)|select < 501',* FROM test_table WHERE test_table_id < 501;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

--bump it to 600
SET @test = 501;
WHILE @test < 600
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT '600 rows (add 100)|select < 600',* FROM test_table WHERE test_table_id < 600;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

--bump it to 700
SET @test = 600;
WHILE @test < 700
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT '700 rows (add 100)|select < 700', * FROM test_table WHERE test_table_id < 700;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

--bump it to 1200
SET @test = 700;
WHILE @test < 1200
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT '1200 rows (add 500)|select < 1200',* FROM test_table WHERE test_table_id < 1200;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;
--DROP TABLE test_table

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

หากต้องการวิเคราะห์ความเบ้คุณต้องเรียกใช้DBCC SHOW_STATISTICS(<stat_object>, <index_name>);(ในสคริปต์ด้านบนโดยไม่มีWITH STAT_HEADER) ในชุดค่าสถิติ / ดัชนีที่คุณต้องการตรวจสอบ วิธีที่รวดเร็วในลูกตาเอียงของคุณจะดู histogram (ชุดผลลัพธ์ที่สาม) EQ_ROWSและตรวจสอบความแปรปรวนในของคุณ ถ้ามันค่อนข้างสอดคล้องกันแล้วความเบ้ของคุณก็น้อย ในการเพิ่มระดับขึ้นคุณดูที่RANGE_ROWSคอลัมน์และดูความแปรปรวนที่มีเนื่องจากการวัดนี้มีจำนวนแถวอยู่ระหว่างแต่ละขั้นตอน สุดท้ายคุณสามารถรับ[All density]ผลลัพธ์จากDENSITY_VECTOR(ชุดผลลัพธ์ที่สอง) และคูณด้วย[Rows Sampled]ค่าในSTAT_HEADER(ชุดผลลัพธ์แรก) และดูว่าการคาดหวังโดยเฉลี่ยจะเป็นอย่างไรสำหรับแบบสอบถามในคอลัมน์นั้น คุณเปรียบเทียบค่าเฉลี่ยกับของคุณEQ_ROWS และหากมีหลายสถานที่ที่แตกต่างกันอย่างมีนัยสำคัญแสดงว่าคุณได้รับเอียง

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

เมื่อคุณมีสถิติที่กรองแล้วคุณสามารถดูความเป็นไปได้ของการอัปเดตสถิติด้วยตนเอง


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