Trong bài đăng trước của tôi, tôi đã khám phá các phương pháp khác nhau để theo dõi các cập nhật tự động cho thống kê để xác định xem chúng có đang ảnh hưởng đến hiệu suất truy vấn hay không. Trong nửa sau của bài viết, tôi đã bao gồm các tùy chọn, một trong số đó là bật cài đặt cơ sở dữ liệu Tự động cập nhật thống kê không đồng bộ. Trong bài đăng này, tôi muốn xem hiệu suất truy vấn thay đổi như thế nào khi cập nhật tự động xảy ra trước khi thực thi truy vấn và điều gì sẽ xảy ra với hiệu suất nếu cập nhật không đồng bộ.
Thiết lập
Tôi bắt đầu với một bản sao của cơ sở dữ liệu AdventureWorks2012, và sau đó tạo một bản sao của bảng SalesOrderHeader với hơn 200 triệu hàng bằng cách sử dụng tập lệnh này. Bảng có chỉ mục được phân nhóm trên SalesOrderID và chỉ mục không được phân nhóm trên CustomerID, OrderDate, SubTotal. [Lưu ý:nếu bạn định thực hiện các bài kiểm tra lặp lại, hãy sao lưu cơ sở dữ liệu này tại thời điểm này để tiết kiệm thời gian]. Sau khi tải dữ liệu và tạo chỉ mục không phân biệt, tôi đã xác minh số lượng hàng và tính toán số hàng (khoảng) cần được sửa đổi để gọi cập nhật tự động.
SELECTOBJECT_NAME ([p]. [object_id]) [TableName], [si]. [name] [IndexName], [au]. [type_desc] [Type], [p]. [row] [RowCount], ([p]. [row] *. 20) + 500 [UpdateThreshold], [au] .total_pages [PageCount], (([au]. [total_pages] * 8) / 1024) / 1024 [TotalGB] FROM [sys ]. [phân vùng] [p] THAM GIA [sys]. [phân bổ_đơn vị] [au] BẬT [p]. [phân vùng] =[au]. [container_id] Tham gia [hệ thống]. [chỉ mục] [si] trên [p] . [object_id] =[si] .object_id và [p]. [index_id] =[si]. [index_id] WHERE [p]. [object_id] =OBJECT_ID (N'Sales.Big_SalesOrderHeader ');
Big_SalesOrderHeader Thông tin CIX và NCI
Tôi cũng đã xác minh tiêu đề thống kê hiện tại cho chỉ mục:
DBCC SHOW_STATISTICS ('Sales.Big_SalesOrderHeader', [IX_Big_SalesOrderHeader_CustomerID_OrderDate_SubTotal]);
Thống kê NCI:Lúc bắt đầu
Sau đó, tôi đã tạo quy trình được lưu trữ mà tôi sẽ sử dụng để thử nghiệm. Đó là một thủ tục đơn giản truy vấn Sales.Big_SalesOrderHeader và tổng hợp dữ liệu bán hàng theo CustomerID và OrderDate để phân tích:
TẠO THỦ TỤC Bán hàng.usp_GetCustomerStats@CustomerID INT, @ StartDate DATETIME, @ EndDate DATETIMEASBEGIN BẬT TÀI KHOẢN; CHỌN CustomerID, DATEPART (YEAR, OrderDate), DATEPART (MONTH, OrderDate), COUNT ([SalesOrderID]) được tính từ [Sales]. [Big_SalesOrderHeader] WHERE CustomerID =@CustomerID VÀ OrderDate GIỮA @StartDate và @EndDate GROUP BY CustomerID, DATEPART (NĂM, Ngày đặt hàng), DATEPART (THÁNG, Ngày đặt hàng) ĐẶT HÀNG THEO DATEPART (NĂM, Ngày đặt hàng), DATEPART (THÁNG, Ngày đặt hàng); HẾT
Cuối cùng, trước khi thực hiện thủ tục được lưu trữ, tôi đã tạo phiên Sự kiện mở rộng để tôi có thể theo dõi thời lượng truy vấn bằng cách sử dụng sp_statement_starting và sp_statement_completed. Tôi cũng đã thêm sự kiện auto_stats, vì mặc dù tôi không mong đợi một bản cập nhật sẽ xảy ra, nhưng tôi muốn sử dụng cùng định nghĩa phiên này sau đó.
TẠO PHIÊN BẢN SỰ KIỆN [StatsUpdate_QueryPerf] TRÊN SERVERADD EVENT sqlserver.auto_stats, THÊM SỰ KIỆN sqlserver.sp_statement_completed (SET collect_statement =(1)), ADD EVENT sqlsername.sp_statement_startingAD gói file StatsUpdate_QueryPerf.xel ') VỚI (MAX_MEMORY =4096 KB, EVENT_RETENTION_MODE =ALLOW_SINGLE_EVENT_LOSS, MAX_DISPATCH_LATENCY =30 SECONDS, MAX_EVENT_SIZE =0 KB, MEMORY_PARTATE_MODE =OFFICE, GOALATE_MODE)Bài kiểm tra
Tôi đã bắt đầu phiên Sự kiện mở rộng, sau đó thực hiện quy trình được lưu trữ nhiều lần, sử dụng các CustomerID khác nhau:
ALTER EVENT SESSION [StatsUpdate_QueryPerf] ON SERVERSTATE =START; GO EXEC Sales.usp_GetCustomerStats 11331, '2012-08-01 00:00:00.000', '2012-08-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 11330, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 11506,' 2012-11-01 00:00:00.000 ',' 2012-11 -30 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 17061, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 11711,' 2013-03- 01 00:00:00.000 ',' 2013-03-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 15131, '2013-02-01 00:00:00.000', '2013-02-28 23:59:59.997 'GOEXEC Sales.usp_GetCustomerStats 29837,' 2012-10-01 00:00:00.000 ',' 2012-10-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats 15750, '2013-03-01 00:00:00.000' , '2013-03-31 23:59:59,997'GOTôi đã xác minh số lượng thực thi và kế hoạch, bằng cách truy vấn bộ đệm ẩn thủ tục:
SELECTOBJECT_NAME ([st]. [objectid]), [st]. [text], [qs]. [execute_count], [qs]. [create_time], [qs]. [last_execution_time], [qs]. [min_worker_time], [qs]. [max_worker_time], [qs]. [min_logical_reads], [qs]. [max_logical_reads], [qs]. [min_elapsed_time], [qs]. [max_elapsed_time], [qp]. [query_plan ] TỪ [sys]. [Dm_exec_query_stats] [qs] ÁP DỤNG CHÉO [sys]. [Dm_exec_sql_text] ([qs] .plan_handle) [st] ÁP DỤNG CHÉO [sys]. [Dm_exec_query_plan] ([qs] .plan_handle) [qs] .plan_handle WHERE [st]. [Text] LIKE '% usp_GetCustomerStats%' VÀ OBJECT_NAME ([st]. [Objectid]) KHÔNG ĐẦY ĐỦ;
Plan Cache:At Start
Kế hoạch truy vấn cho thủ tục được lưu trữ, sử dụng SQL Sentry Plan ExplorerTôi có thể thấy rằng kế hoạch đã được tạo vào 2014-04-08 18:59:39.850. Với kế hoạch trong bộ nhớ cache, tôi đã dừng phiên Sự kiện mở rộng:
PHIÊN BẢN SỰ KIỆN ALTER [StatsUpdate_QueryPerf] ON SERVERSTATE =STOP;Tiếp theo, tôi đã thêm khoảng 47 triệu hàng dữ liệu vào bảng bằng cách sử dụng tập lệnh này, vượt quá ngưỡng cần thiết để làm mất hiệu lực thống kê hiện tại. Sau khi thêm dữ liệu, tôi đã xác minh số hàng trong bảng:
Big_SalesOrderHeader CI:Sau khi tải dữ liệuTrước khi chạy lại quy trình đã lưu trữ của mình, tôi đã kiểm tra bộ nhớ cache của gói để đảm bảo không có gì thay đổi và xác minh rằng số liệu thống kê chưa được cập nhật. Hãy nhớ rằng, ngay cả khi thống kê đã bị vô hiệu tại thời điểm này, chúng sẽ không cập nhật cho đến khi một truy vấn sử dụng thống kê được thực thi (để tham khảo:Hiểu khi nào thống kê sẽ tự động cập nhật). Đối với bước cuối cùng, tôi bắt đầu lại phiên Sự kiện mở rộng và sau đó chạy quy trình đã lưu trữ nhiều lần. Sau những lần thực thi đó, tôi đã kiểm tra lại bộ nhớ cache của gói:
Plan Cache:Sau khi tải dữ liệuSố lần thực thi lại là 8 và nếu chúng ta nhìn vào thời gian tạo của kế hoạch, chúng ta có thể thấy nó đã được thay đổi thành 2014-04-08 19:32:52.913. Nếu chúng tôi kiểm tra kế hoạch, chúng tôi có thể thấy rằng nó giống nhau, mặc dù kế hoạch đã được biên dịch lại:
Kế hoạch truy vấn cho thủ tục được lưu trữ, sử dụng SQL Sentry Plan ExplorerPhân tích kết quả sự kiện mở rộng
Tôi lấy tệp Sự kiện mở rộng đầu tiên - trước khi dữ liệu được tải - và mở nó trong SSMS, sau đó áp dụng bộ lọc để chỉ các câu lệnh từ quy trình được lưu trữ mới được liệt kê:
Đầu ra sự kiện mở rộng:Sau khi thực thi SP ban đầuBạn có thể thấy rằng có tám (8) lần thực thi thủ tục được lưu trữ, với thời lượng truy vấn thay đổi một chút.
Tôi lấy tệp Sự kiện mở rộng thứ hai - sau khi dữ liệu được tải - mở tệp SSMS và lọc lại để chỉ các câu lệnh từ thủ tục được lưu trữ, cũng như các sự kiện auto_stats mới được liệt kê:
Đầu ra sự kiện mở rộng:Thực thi SP sau khi tải dữ liệuĐầu ra bị cắt bớt, vì nó không cần thiết để hiển thị kết quả chính. Các mục được đánh dấu màu xanh lam đại diện cho lần thực thi đầu tiên của thủ tục được lưu trữ và lưu ý rằng có nhiều bước - cập nhật số liệu thống kê là một phần của quá trình thực thi. Câu lệnh SELECT bắt đầu (đính kèm_activity_id.seq =3) và các cập nhật cho thống kê sau đó sẽ thực thi. Trong ví dụ của chúng tôi, chúng tôi thực sự có cập nhật cho ba số liệu thống kê. Khi bản cập nhật cuối cùng hoàn tất (Attach_activity_id.seq =11), thì quy trình đã lưu trữ sẽ bắt đầu và hoàn tất (Attach_activity_id.seq =13 và Attach_activity_id.seq =14). Điều thú vị là có sự kiện sp_statement_starting thứ hai cho thủ tục được lưu trữ (có lẽ là sự kiện đầu tiên bị bỏ qua), do đó, tổng thời lượng cho thủ tục được lưu trữ được tính toán không có cập nhật số liệu thống kê.
Trong trường hợp này, việc thống kê tự động cập nhật ngay lập tức - nghĩa là khi truy vấn sử dụng thống kê không hợp lệ thực thi - khiến truy vấn chạy lâu hơn, mặc dù thời lượng truy vấn dựa trên sự kiện sp_statement_completed vẫn nhỏ hơn 14000. Kết quả cuối cùng là không có lợi cho hiệu suất truy vấn, vì kế hoạch hoàn toàn giống nhau trước và sau khi cập nhật thống kê. Trong trường hợp này, kế hoạch truy vấn và thời lượng thực thi không thay đổi sau khi thêm dữ liệu vào bảng, vì vậy cập nhật thống kê chỉ cản trở hiệu suất của nó. Bây giờ, hãy xem điều gì sẽ xảy ra khi chúng tôi bật tùy chọn Tự động cập nhật thống kê không đồng bộ.
Thử nghiệm, Phiên bản 2
Chúng tôi bắt đầu bằng cách khôi phục lại bản sao lưu mà tôi đã chụp trước khi chúng tôi bắt đầu thử nghiệm đầu tiên. Tôi đã tạo lại quy trình được lưu trữ và sau đó thay đổi tùy chọn cơ sở dữ liệu để cập nhật thống kê không đồng bộ:
USE [master]; GOALTER DATABASE [AdventureWorks2012_Big] ĐẶT AUTO_UPDATE_STATISTICS_ASYNC BẬT VỚI NO_WAITGOTôi đã bắt đầu phiên Sự kiện mở rộng và thực hiện lại quy trình được lưu trữ nhiều lần, sử dụng các CustomerID khác nhau:
ALTER EVENT SESSION [StatsUpdate_QueryPerf] ON SERVERSTATE =START; GO EXEC Sales.usp_GetCustomerStats11331, '2012-08-01 00:00:00.000', '2012-08-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats11330, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats11506,' 2012-11-01 00:00:00.000 ',' 2012-11-30 23 :59:59.997'GOEXEC Sales.usp_GetCustomerStats17061, '2013-01-01 00:00:00.000', '2013-01-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats11711,' 2013-03-01 00:00:00.000 ',' 2013-03-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats15131, '2013-02-01 00:00:00.000', '2013-02-28 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats29837, '2012-10-01 00:00:00.000', '2012-10-31 23:59:59.997'GOEXEC Sales.usp_GetCustomerStats15750,' 2013-03-01 00:00:00.000 ',' 2013-03-31 23 :59:59,997'GOTôi đã xác minh số lượng thực thi và kế hoạch, bằng cách truy vấn bộ đệm ẩn thủ tục:
Plan Cache:At Start, Test 2
Kế hoạch truy vấn cho thủ tục được lưu trữ, sử dụng SQL Sentry Plan ExplorerĐối với thử nghiệm này, kế hoạch đã được tạo vào 2014-04-08 21:15:55.490. Tôi đã dừng phiên Sự kiện mở rộng và lại thêm khoảng 47 triệu hàng dữ liệu vào bảng, sử dụng cùng một truy vấn như trước đây.
Sau khi dữ liệu đã được thêm vào, tôi đã kiểm tra bộ nhớ cache của gói để đảm bảo không có gì thay đổi và xác minh rằng số liệu thống kê chưa được cập nhật. Cuối cùng, tôi bắt đầu lại phiên Sự kiện mở rộng và sau đó chạy quy trình đã lưu trữ thêm tám lần nữa. Lần xem cuối cùng vào bộ nhớ cache của kế hoạch cho thấy số lượng thực thi là 16 và thời gian tạo là 2014-04-08 21:15:55.490. Thực hiện_count và create_time chứng minh rằng số liệu thống kê chưa được cập nhật, vì kế hoạch chưa được xóa khỏi bộ nhớ cache (nếu có, chúng tôi sẽ có create_time sau đó và thực hiện_count là 8).
Plan Cache:Sau khi tải dữ liệu, thử nghiệm 2Nếu chúng tôi mở đầu ra Sự kiện mở rộng từ sau khi tải dữ liệu trong SSMS và lại lọc để chúng tôi chỉ thấy các câu lệnh từ thủ tục được lưu trữ, cũng như các sự kiện auto_stats, chúng tôi nhận thấy điều này (lưu ý rằng đầu ra được chia thành hai ảnh chụp màn hình):
Đầu ra sự kiện mở rộng:Thử nghiệm 2, Thực thi SP sau khi tải dữ liệu, phần I
Đầu ra sự kiện mở rộng:Thử nghiệm 2, Thực thi SP sau khi tải dữ liệu, phần IICác sự kiện để thực hiện lệnh gọi đầu tiên của thủ tục được lưu trữ được đánh dấu bằng màu xanh lam - chúng bắt đầu lúc 2014-04-08 21:54:14.9480607 và có bảy (7) sự kiện. Lưu ý rằng có ba (3) sự kiện auto_stats, nhưng không có sự kiện nào trong số đó thực sự hoàn thành, như chúng ta đã thấy khi tùy chọn Tự động cập nhật thống kê không đồng bộ bị tắt. Bạn sẽ nhận thấy rằng cập nhật tự động bắt đầu cho một trong các thống kê gần như ngay lập tức (2014-04-08 21:54:14.9481288) và đó là ba sự kiện có dòng chữ màu đỏ 'Stat Update # 1' bên cạnh chúng. Cập nhật thống kê đó kết thúc lúc 2014-04-08 21:54:16.5392219, chỉ dưới hai giây sau khi bắt đầu, nhưng sau khi tất cả các lần thực thi khác của quy trình đã hoàn tất. Đây là lý do tại sao thực thi_count từ sys.dm_exec_query_stats hiển thị 16. Từ đầu ra XE, chúng ta có thể thấy rằng các cập nhật thống kê khác sau đó đã hoàn tất (Cập nhật thống kê # 2 và Cập nhật thống kê # 3). Tất cả các bản cập nhật đều không đồng bộ với quá trình thực thi thủ tục được lưu trữ ban đầu.
Tóm tắt
Như bạn có thể thấy, cập nhật tự động cho thống kê có khả năng ảnh hưởng tiêu cực đến hiệu suất truy vấn. Mức độ tác động sẽ phụ thuộc vào lượng dữ liệu phải đọc để cập nhật số liệu thống kê và tài nguyên hệ thống. Trong một số trường hợp, hiệu suất truy vấn chỉ tăng theo mili giây và rất có thể người dùng không thể nhận thấy được. Những lần khác, thời lượng có thể tăng lên đáng kể, sau đó ảnh hưởng đến trải nghiệm của người dùng cuối. Trong trường hợp kế hoạch truy vấn không thay đổi sau khi cập nhật thống kê, bạn nên xem xét bật tùy chọn Tự động cập nhật thống kê không đồng bộ để giảm thiểu tác động đến hiệu suất truy vấn.