Đây là một whitepaper khi auto_update thống kê xảy ra . Dưới đây là các điểm nổi bật cập nhật tự động vis-a-vis để thống kê:
- Kích thước bảng đã đi từ 0 đến> 0 hàng (kiểm tra 1).
- Số lượng hàng trong bảng khi số liệu thống kê được thu thập là 500 hoặc ít hơn và colmodctr của cột hàng đầu của đối tượng thống kê đã thay đổi hơn 500 kể từ đó (thử nghiệm 2).
- Bảng có hơn 500 hàng khi số liệu thống kê được thu thập và colmodctr của cột hàng đầu của đối tượng thống kê đã thay đổi hơn 500 + 20% số lượng hàng trong bảng khi thu thập số liệu thống kê (kiểm tra 3) .
Vì vậy, @JNK đã đưa ra quan điểm trong một nhận xét rằng nếu bạn có 1 tỷ hàng trong một bảng, bạn cần phải có 20.000.5000 ghi vào cột đầu tiên trong thống kê để kích hoạt cập nhật.
Hãy lấy cấu trúc sau:
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);
Bây giờ chúng ta có thể kiểm tra để xem những gì đã xảy ra trong đất thống kê.
select *
from sys.stats
where object_id = OBJECT_ID('dbo.test_table')
Tuy nhiên, để xem đây có phải là một đối tượng thống kê có ý nghĩa hay không, chúng ta cần phải:
dbcc show_statistics('dbo.test_table',cix_test_table)
Vì vậy, thống kê này đã không được cập nhật. Đó là bởi vì có vẻ như số liệu thống kê không được cập nhật cho đến khi SELECT
xảy ra và thậm chí sau đó SELECT
phải vượt ra ngoài những gì SQL Server có trong biểu đồ của nó. Đây là một kịch bản thử nghiệm mà tôi đã chạy để kiểm tra điều này:
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
Thay vì mù quáng vô hiệu hóa số liệu thống kê auto_update, tôi sẽ thử kiểm tra tập dữ liệu của bạn xem có bị lệch không. Nếu dữ liệu của bạn thể hiện độ lệch đáng kể, thì bạn cần xem xét việc tạo số liệu thống kê được lọc và sau đó quyết định xem việc quản lý cập nhật thống kê theo cách thủ công có phải là hướng hành động chính xác hay không.
Để phân tích cho độ lệch, bạn cần chạy DBCC SHOW_STATISTICS(<stat_object>, <index_name>);
(trong đoạn mã trên mà không có WITH STAT_HEADER
) trên tổ hợp chỉ số / chỉ số cụ thể mà bạn muốn kiểm tra. Một cách nhanh chóng để nhãn cầu xiên của bạn sẽ là nhìn vào biểu đồ (tập kết quả thứ ba) và kiểm tra phương sai trong của bạn EQ_ROWS
. Nếu nó khá nhất quán thì độ lệch của bạn là tối thiểu. Để đẩy nó lên, bạn nhìn vào RANGE_ROWS
cột và nhìn vào phương sai ở đó vì điều này đo lường có bao nhiêu hàng tồn tại giữa mỗi bước. Cuối cùng, bạn có thể lấy [All density]
kết quả từ DENSITY_VECTOR
(tập kết quả thứ hai) và nhân [Rows Sampled]
giá trị đó với giá trị trong STAT_HEADER
(tập kết quả đầu tiên) và xem kỳ vọng trung bình sẽ là bao nhiêu cho một truy vấn trên cột đó. Bạn so sánh mức trung bình đó vớiEQ_ROWS
và nếu có nhiều nơi thay đổi đáng kể, thì bạn đã bị lệch.
Nếu bạn thấy rằng bạn có độ lệch, thì bạn cần xem xét việc tạo một số thống kê được lọc trên các phạm vi có mức rất cao RANGE_ROWS
để bạn có thể đưa ra các bước bổ sung để ước tính tốt hơn về các giá trị đó.
Khi bạn có các số liệu thống kê được lọc này, bạn có thể xem xét khả năng cập nhật thống kê theo cách thủ công.