Thống kê biến mất sau khi cập nhật gia tăng


21

Chúng tôi có một cơ sở dữ liệu SQL Server được phân vùng lớn sử dụng số liệu thống kê gia tăng. Tất cả các chỉ mục được phân vùng phù hợp. Khi chúng tôi cố gắng xây dựng lại một phân vùng trực tuyến bằng phân vùng, tất cả các số liệu thống kê sẽ biến mất sau khi chỉ mục được xây dựng lại.

Dưới đây là tập lệnh để sao chép sự cố trong SQL Server 2014 với cơ sở dữ liệu AdventureWorks2014.

--Example against AdventureWorks2014 Database

CREATE PARTITION FUNCTION TransactionRangePF1 (DATETIME)
AS RANGE RIGHT FOR VALUES 
(
   '20130501', '20130601', '20130701', '20130801', 
   '20130901', '20131001', '20131101', '20131201', 
   '20140101', '20140201', '20140301'
);
GO

CREATE PARTITION SCHEME TransactionsPS1 AS PARTITION TransactionRangePF1 TO 
(
  [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], 
  [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], 
  [PRIMARY], [PRIMARY], [PRIMARY]
);
GO

CREATE TABLE dbo.TransactionHistory 
(
  TransactionID        INT      NOT NULL, -- not bothering with IDENTITY here
  ProductID            INT      NOT NULL,
  ReferenceOrderID     INT      NOT NULL,
  ReferenceOrderLineID INT      NOT NULL DEFAULT (0),
  TransactionDate      DATETIME NOT NULL DEFAULT (GETDATE()),
  TransactionType      NCHAR(1) NOT NULL,
  Quantity             INT      NOT NULL,
  ActualCost           MONEY    NOT NULL,
  ModifiedDate         DATETIME NOT NULL DEFAULT (GETDATE()),
  CONSTRAINT CK_TransactionType 
    CHECK (UPPER(TransactionType) IN (N'W', N'S', N'P'))
) 
ON TransactionsPS1 (TransactionDate);


INSERT INTO dbo.TransactionHistory
SELECT * FROM Production.TransactionHistory
--  SELECT * FROM sys.partitions
--  WHERE object_id = OBJECT_ID('dbo.TransactionHistory');

CREATE NONCLUSTERED INDEX IDX_ProductId ON dbo.TransactionHistory (ProductId) 
  WITH (DATA_COMPRESSION = ROW, STATISTICS_INCREMENTAL=ON)  
  ON TransactionsPS1 (TransactionDate)

DBCC SHOW_STATISTICS('dbo.TransactionHistory', IDX_ProductId);
PRINT 'Stats are avialable'  

ALTER INDEX [IDX_ProductId] ON [dbo].[TransactionHistory] REBUILD 
  PARTITION = 9 WITH (ONLINE = ON , DATA_COMPRESSION = ROW)

PRINT 'After online index rebuild by partition stats are now gone'
DBCC SHOW_STATISTICS('dbo.TransactionHistory', IDX_ProductId);

PRINT 'Rebuild the stats with a rebuild for all paritions (this works)' 
ALTER INDEX [IDX_ProductId] ON [dbo].[TransactionHistory] REBUILD 
  PARTITION = ALL WITH (ONLINE = ON , DATA_COMPRESSION = ROW, 
  STATISTICS_INCREMENTAL = ON)

PRINT 'Stats are back'
DBCC SHOW_STATISTICS('dbo.TransactionHistory', IDX_ProductId);

PRINT 'Works correctly for an offline rebuild by partition'
ALTER INDEX [IDX_ProductId] ON [dbo].[TransactionHistory] REBUILD 
  PARTITION = 9 WITH (ONLINE = OFF , DATA_COMPRESSION = ROW)

    --stats still there  
DBCC SHOW_STATISTICS('dbo.TransactionHistory', IDX_ProductId);

ALTER INDEX [IDX_ProductId] ON [dbo].[TransactionHistory] REBUILD 
  PARTITION = 9 WITH (ONLINE = ON , DATA_COMPRESSION = ROW)

DBCC SHOW_STATISTICS('dbo.TransactionHistory', IDX_ProductId);
PRINT' stats are gone!!!!!!'

Như được hiển thị, chúng tôi không thể xây dựng lại các chỉ mục bằng cách phân vùng trực tuyến mà không mất tất cả các số liệu thống kê cho chỉ mục. Đây là một vấn đề bảo trì lớn đối với chúng tôi. Dường như tùy chọn tăng số liệu thống kê cần phải là một phần của cú pháp xây dựng lại chỉ mục duy nhất hoặc tùy chọn trực tuyến cần xử lý chính xác như tùy chọn ngoại tuyến.

Xin vui lòng cho tôi biết nếu tôi đang thiếu một cái gì đó?

Cập nhật:

Theo như nhu cầu của chúng tôi về số liệu thống kê gia tăng: Chúng tôi đang phân vùng trên id khách hàng nội bộ chứ không phải ngày. Vì vậy, khi một ứng dụng khách mới được đưa vào (tải dữ liệu lớn), chúng tôi chỉ cần cập nhật các số liệu thống kê cho phân vùng và nhanh chóng tránh mọi kế hoạch xấu xí được tạo ra cho khách hàng mới này. Tôi nghĩ rằng tôi sẽ gửi nó với Microsoft như một lỗi và xem họ nói gì và đi với giải pháp chỉ cần lấy mẫu lại các số liệu thống kê cho phân vùng đó.

Kết nối báo cáo lỗi:

Thống kê biến mất sau khi xây dựng lại chỉ mục trực tuyến với số liệu thống kê gia tăng

Cập nhật: Microsoft đã xác nhận rằng đó là một lỗi.


1
Cập nhật: Microsoft đã gửi cho tôi một email sáng nay rằng lỗi này sẽ được sửa trong bản cập nhật CU tiếp theo cho SQL 2014.
JasonR

Bạn có biết CUs nào đã sửa nó hay KB mà họ đã báo cáo trong email đó không? Cố gắng xem khi nó đã được sửa chữa.
mbourgon

1
Khá chắc chắn đó là lỗi VSTS số 8046729 KB Số bài viết 3194959 là một phần của CU 9 cho SQL Server 2014 SP1. Một liên kết đến KB ở đây .
JasonR

Vâng, có vẻ như nó - và vừa được sửa vào 2016SP1 vào tháng trước. Rất rất cảm ơn!
mbourgon

Sửa lỗi: vừa sửa trong 2016 SP1 CU2. Nó xảy ra vào 2016 SP1 CU1.
mbourgon

Câu trả lời:


17

Bạn không chắc chắn nếu đó là một lỗi, cho mỗi gia nhập , nhưng nó chắc chắn là một sự xuất hiện thú vị. Xây dựng lại phân vùng trực tuyến là mới trong SQL Server 2014, vì vậy có thể có một số nội bộ để sắp xếp với điều này.

Đây là lời giải thích tốt nhất của tôi cho bạn. Thống kê tăng dần hoàn toàn yêu cầu tất cả các phân vùng được lấy mẫu ở cùng một tốc độ để khi động cơ hợp nhất các trang thống kê, có thể tin tưởng rằng phân phối được lấy mẫu là tương đương. REBUILDnhất thiết phải lấy mẫu dữ liệu với tỷ lệ mẫu 100%. Không có gì đảm bảo rằng tỷ lệ mẫu 100% trên phân vùng 9 sẽ luôn là tỷ lệ mẫu chính xác của phần còn lại của các phân vùng. Bởi vì điều này, nó xuất hiện như thể động cơ không thể hợp nhất các mẫu và bạn kết thúc với một blob thống kê trống. Tuy nhiên, đối tượng thống kê vẫn còn đó:

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'

Bạn có thể điền vào blob thông qua bất kỳ số lượng phương tiện:

UPDATE STATISTICS dbo.TransactionHistory (IDX_ProductId) WITH RESAMPLE;

hoặc là

UPDATE STATISTICS dbo.TransactionHistory (IDX_ProductId) WITH RESAMPLE ON PARTITIONS (9);

hoặc bạn có thể đợi AutoStats cập nhật vào phần biên dịch đầu tiên của gói truy vấn bằng cách sử dụng đối tượng đó:

-- look at my creative query
select * 
from dbo.TransactionHistory
where TransactionDate = '20140101';

Đã nói tất cả những điều đó, bài viết khai sáng này của Erin Stellato nhấn mạnh những gì đã được coi là một thiếu sót lớn của các chỉ số gia tăng. Dữ liệu cấp phân vùng của chúng không được trình tối ưu hóa sử dụng trong việc tạo kế hoạch truy vấn, làm giảm lợi ích giả định của thống kê gia tăng. Vậy thì, lợi ích hiện tại của thống kê gia tăng là gì? Tôi đã gửi rằng tiện ích chính của họ là khả năng lấy mẫu các bảng lớn một cách nhất quán hơn với tỷ lệ cao hơn so với thống kê truyền thống.

Sử dụng ví dụ của bạn, đây là cách mọi thứ trông:

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.

Một bản cập nhật thống kê toàn màn hình về chi phí thống kê gia tăng là 131 ms. Một bản cập nhật thống kê fullscan về thống kê không liên kết phân vùng có chi phí 66 ms. Thống kê không liên kết chậm hơn rất có thể do chi phí phát sinh với việc hợp nhất các trang thống kê riêng lẻ trở lại biểu đồ chính. Tuy nhiên, bằng cách sử dụng đối tượng thống kê phù hợp với phân vùng, chúng ta có thể cập nhật một phân vùng và hợp nhất nó trở lại vào biểu đồ chính trong 5 ms. Vì vậy, tại thời điểm này, quản trị viên với số liệu thống kê gia tăng phải đối mặt với một quyết định. Họ có thể giảm thời gian bảo trì thống kê tổng thể bằng cách chỉ cập nhật các phân vùng theo truyền thống cần được cập nhật hoặc họ có thể thử nghiệm với tỷ lệ mẫu cao hơn để họ có thể lấy được nhiều hàng hơn trong cùng khoảng thời gian với khung thời gian bảo trì trước đó. Cái trước cho phép phòng thở trong cửa sổ bảo trì, cái sau có thể đẩy số liệu thống kê trên một cái bàn rất lớn đến nơi mà các truy vấn có kế hoạch tốt hơn dựa trên số liệu thống kê chính xác hơn. Đây không phải là một sự đảm bảo và số dặm của bạn có thể thay đổi.

Người đọc có thể thấy rằng 66 ms không phải là thời gian cập nhật thống kê đau đớn trên bảng này vì vậy tôi đã thử thiết lập thử nghiệm trên bộ dữ liệu stackexchange. Có 6.418.608 bài đăng (không bao gồm các bài đăng StackOverflow và tất cả các bài đăng từ năm 2012 - một lỗi dữ liệu của tôi) trong kết xuất gần đây mà tôi đã tải xuống.

Tôi đã phân vùng dữ liệu bởi [CreationDate]vì ... bản demo.

Dưới đây là một số thời gian cho một số kịch bản tiêu chuẩn khá (100% - xây dựng lại chỉ mục, mặc định - tự động cập nhật thống kê hoặc UPDATE STATISTICSkhông có tỷ lệ mẫu được chỉ định:

  • Tạo thống kê không tăng dần với Fullscan: thời gian CPU = 23500 ms, thời gian trôi qua = 22521 ms.
  • Tạo Fullscan thống kê gia tăng: Thời gian CPU = 20406 ms, thời gian trôi qua = 15413 ms.
  • Cập nhật thống kê không tăng với tỷ lệ mẫu mặc định: Thời gian CPU = 406 ms, thời gian trôi qua = 408 ms.
  • Cập nhật thống kê tăng dần với tốc độ mẫu mặc định: Thời gian CPU = 453 ms, thời gian trôi qua = 507 ms.

Giả sử chúng tôi tinh vi hơn các kịch bản mặc định này và đã quyết định rằng tỷ lệ mẫu 10% là tỷ lệ tối thiểu sẽ đưa chúng tôi các kế hoạch chúng tôi cần trong khi duy trì thời gian bảo trì theo khung thời gian hợp lý.

  • Cập nhật Thống kê không tăng với mẫu 10 phần trăm: Thời gian CPU = 2344 ms, thời gian trôi qua = 2441 ms.
  • Cập nhật Thống kê tăng dần với mẫu 10 phần trăm: Thời gian CPU = 2344 ms, thời gian trôi qua = 2388 ms.

Cho đến nay không có lợi ích rõ ràng để có một thống kê gia tăng. Tuy nhiên, nếu chúng tôi tận dụng DMV không có giấy tờ sys.dm_db_stats_properties_internal() (bên dưới), bạn có thể hiểu rõ hơn về phân vùng nào bạn có thể muốn cập nhật. Giả sử chúng tôi đã thực hiện thay đổi dữ liệu trong phân vùng 3 và chúng tôi muốn đảm bảo số liệu thống kê mới cho các truy vấn đến. Dưới đây là các lựa chọn của chúng tôi:

  • Cập nhật Không tăng theo mặc định (cũng là hành vi mặc định của Cập nhật thống kê tự động): 408 ms.
  • Cập nhật Không tăng ở mức 10%: 2441 ms.
  • Cập nhật số liệu thống kê tăng dần, phân vùng 3 với mẫu lại (10% - tỷ lệ mẫu được xác định của chúng tôi): thời gian CPU = 63 ms, thời gian trôi qua = 63 ms.

Đây là nơi chúng ta cần đưa ra quyết định. Chúng ta có giành chiến thắng trong 63 ms. cập nhật dựa trên phân vùng, hoặc chúng ta có thể tăng tỷ lệ mẫu cao hơn nữa không? Giả sử chúng tôi sẵn sàng lấy 50% số lần lấy mẫu ban đầu theo thống kê gia tăng:

  • Cập nhật thống kê tăng dần ở mức 50%: thời gian trôi qua = 16840 ms.
  • Cập nhật thống kê tăng dần, phân vùng 3 với mẫu lại (50% - thời gian cập nhật mới của chúng tôi): thời gian trôi qua = 295 ms.

Chúng tôi có thể lấy mẫu nhiều dữ liệu hơn, có thể thiết lập trình tối ưu hóa để dự đoán tốt hơn về dữ liệu của chúng tôi (mặc dù nó không sử dụng thống kê cấp phân vùng) và chúng tôi có thể thực hiện việc này nhanh hơn bây giờ khi chúng tôi có thống kê gia tăng.

Một điều thú vị cuối cùng để tìm ra, mặc dù. Điều gì về cập nhật thống kê đồng bộ? Tỷ lệ mẫu 50% có được bảo toàn ngay cả khi autostats khởi động không?

Tôi đã xóa dữ liệu khỏi phân vùng 3 và chạy truy vấn trên CreationDate và kiểm tra sau đó kiểm tra tỷ lệ với cùng một truy vấn bên dưới. Tỷ lệ mẫu 50% được bảo tồn.

Vì vậy, câu chuyện dài ngắn: Thống kê tăng dần có thể là một công cụ hữu ích với lượng suy nghĩ và công việc thiết lập ban đầu phù hợp. Tuy nhiên, bạn phải biết vấn đề mà bạn đang cố gắng giải quyết và sau đó bạn cần giải quyết nó một cách thích hợp. Nếu bạn đang có ước tính về số lượng thẻ xấu, bạn thể có được các kế hoạch tốt hơn với tỷ lệ mẫu chiến lược và một số can thiệp được đầu tư. Tuy nhiên, bạn chỉ nhận được một phần nhỏ lợi ích vì biểu đồ được sử dụng là trang thống kê đơn, được hợp nhất và không phải là thông tin cấp phân vùng. Nếu bạn cảm thấy đau trong cửa sổ bảo trì, thì có thể số liệu thống kê gia tăng có thể giúp bạn, nhưng có lẽ nó sẽ yêu cầu bạn thiết lập quy trình can thiệp bảo trì cảm ứng cao. Bất kể,:

  • Thống kê được tạo với các chỉ mục không được liên kết phân vùng với bảng cơ sở.
  • Thống kê được tạo trên cơ sở dữ liệu thứ cấp Luôn có thể đọc được.
  • Thống kê được tạo trên cơ sở dữ liệu chỉ đọc.
  • Thống kê được tạo trên các chỉ mục được lọc.
  • Thống kê được tạo trên lượt xem.
  • Thống kê được tạo trên các bảng nội bộ.
  • Thống kê được tạo bằng các chỉ mục không gian hoặc chỉ mục XML.

Hi vọng điêu nay co ich

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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.