Database
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Database

Nhiều kế hoạch cho một truy vấn giống hệt nhau

Tôi thường thấy mọi người đấu tranh với SQL Server khi họ thấy hai kế hoạch thực thi khác nhau cho những gì họ tin là cùng một truy vấn. Thông thường điều này được phát hiện sau những lần quan sát khác, chẳng hạn như thời gian thực hiện rất khác nhau. Tôi nói rằng họ tin rằng đó là cùng một truy vấn bởi vì, đôi khi đúng như vậy và đôi khi không.

Một trong những trường hợp phổ biến nhất là khi họ đang kiểm tra một truy vấn trong SSMS và nhận được một gói khác với gói họ nhận được từ ứng dụng của họ. Có hai yếu tố tiềm ẩn đang diễn ra ở đây (cũng có thể có liên quan khi KHÔNG so sánh giữa ứng dụng và SSMS):

  1. Ứng dụng hầu như luôn có SET khác nhau cài đặt hơn SSMS (đây là những thứ như ARITHABORT , ANSI_NULLSQUOTED_IDENTIFIER ). Điều này buộc SQL Server phải lưu trữ hai kế hoạch riêng biệt; Erland Sommarskog đã giải quyết vấn đề này rất chi tiết trong bài viết của mình, Chậm trong ứng dụng, Nhanh trong SSMS?
  2. Các tham số được ứng dụng sử dụng khi bản sao kế hoạch của nó được biên dịch lần đầu tiên có thể rất khác và dẫn đến một kế hoạch khác, so với những thông số được sử dụng trong lần đầu tiên truy vấn được chạy từ SSMS - đây được gọi là đánh giá tham số . Erland cũng nói sâu về vấn đề đó và tôi sẽ không nhắc lại các đề xuất của anh ấy, nhưng tóm tắt lại bằng cách nhắc bạn rằng kiểm tra truy vấn của ứng dụng trong SSMS không phải lúc nào cũng hữu ích, vì nó không có khả năng là một thử nghiệm táo.

Có một vài tình huống khác hơi mơ hồ mà tôi đưa ra trong bài nói về Thói quen xấu &Các phương pháp hay nhất của mình. Đây là những trường hợp các kế hoạch không khác nhau, nhưng có nhiều bản sao của cùng một kế hoạch sẽ làm phình bộ nhớ đệm của kế hoạch. Tôi nghĩ tôi nên đề cập đến họ ở đây vì họ luôn khiến rất nhiều người ngạc nhiên.

cAsE và khoảng trắng rất quan trọng

SQL Server băm văn bản truy vấn thành định dạng nhị phân, có nghĩa là mọi ký tự đơn lẻ trong văn bản truy vấn đều rất quan trọng. Hãy thực hiện các truy vấn đơn giản sau:

USE AdventureWorks2014;
DBCC FREEPROCCACHE WITH NO_INFOMSGS;
GO
SELECT StoreID FROM Sales.Customer;
GO -- original query
GO
SELECT  StoreID FROM Sales.Customer;
GO ----^---- extra space
GO
SELECT storeid FROM sales.customer;
GO ---- lower case names
GO
select StoreID from Sales.Customer;
GO ---- lower case keywords
GO

Chúng tạo ra các kết quả giống hệt nhau, rõ ràng và tạo ra cùng một kế hoạch. Tuy nhiên, nếu chúng ta nhìn vào những gì chúng ta có trong bộ nhớ cache của gói:

SELECT t.[text], p.size_in_bytes, p.usecounts
 FROM sys.dm_exec_cached_plans AS p
 CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t
 WHERE LOWER(t.[text]) LIKE N'%sales'+'.'+'customer%';

Kết quả thật đáng tiếc:

Vì vậy, trong trường hợp này, rõ ràng là trường hợp và khoảng trắng là rất quan trọng. Tôi đã nói về điều này chi tiết hơn vào tháng 5 năm ngoái.

Tham chiếu lược đồ rất quan trọng

Trước đây, tôi đã viết blog về tầm quan trọng của việc chỉ định tiền tố lược đồ khi tham chiếu đến bất kỳ đối tượng nào, nhưng tại thời điểm đó, tôi không hoàn toàn biết rằng nó cũng có ý nghĩa về bộ nhớ cache kế hoạch.

Hãy xem xét một trường hợp rất đơn giản, trong đó chúng ta có hai người dùng với các lược đồ mặc định khác nhau và họ chạy cùng một văn bản truy vấn, không tham chiếu được đối tượng theo lược đồ của nó:

USE AdventureWorks2014;
DBCC FREEPROCCACHE WITH NO_INFOMSGS;
GO
 
CREATE USER SQLPerf1 WITHOUT LOGIN WITH DEFAULT_SCHEMA = Sales;
CREATE USER SQLPerf2 WITHOUT LOGIN WITH DEFAULT_SCHEMA = Person;
GO
 
CREATE TABLE dbo.AnErrorLog(id INT);
GRANT SELECT ON dbo.AnErrorLog TO SQLPerf1, SQLPerf2;
GO
 
EXECUTE AS USER = N'SQLPerf1';
GO
SELECT id FROM AnErrorLog;
GO
REVERT;
GO
EXECUTE AS USER = N'SQLPerf2';
GO
SELECT id FROM AnErrorLog;
GO
REVERT;
GO

Bây giờ, nếu chúng ta xem xét bộ nhớ cache của kế hoạch, chúng ta có thể lấy sys.dm_exec_plan_attributes để biết chính xác lý do tại sao chúng tôi nhận được hai gói khác nhau cho các truy vấn giống hệt nhau:

SELECT t.[text], p.size_in_bytes, p.usecounts, 
  [schema_id] = pa.value, 
  [schema] = s.name
FROM sys.dm_exec_cached_plans AS p
CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t
CROSS APPLY sys.dm_exec_plan_attributes(p.plan_handle) AS pa
INNER JOIN sys.schemas AS s ON s.[schema_id] = pa.value
WHERE t.[text] LIKE N'%AnError'+'Log%' 
AND pa.attribute = N'user_id';

Kết quả:

Và nếu bạn chạy lại tất cả nhưng thêm dbo. tiền tố cho cả hai truy vấn, bạn sẽ thấy chỉ có một gói được sử dụng hai lần. Điều này trở thành một đối số rất thuyết phục để luôn tham chiếu đầy đủ các đối tượng.

ĐẶT cài đặt redux

Lưu ý thêm, bạn có thể sử dụng cách tiếp cận tương tự để xác định xem SET cài đặt khác nhau cho hai hoặc nhiều phiên bản của cùng một truy vấn. Trong trường hợp này, chúng tôi đang điều tra các truy vấn liên quan đến nhiều kế hoạch được tạo bởi các lệnh gọi khác nhau đến cùng một thủ tục được lưu trữ, nhưng bạn cũng có thể xác định chúng bằng văn bản truy vấn hoặc hàm băm truy vấn.

SELECT p.plan_handle, p.usecounts, p.size_in_bytes, 
  set_options = MAX(a.value)
FROM sys.dm_exec_cached_plans AS p
CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t
CROSS APPLY sys.dm_exec_plan_attributes(p.plan_handle) AS a
WHERE t.objectid = OBJECT_ID(N'dbo.procedure_name')
AND a.attribute = N'set_options'
GROUP BY p.plan_handle, p.usecounts, p.size_in_bytes;

Nếu bạn có nhiều kết quả ở đây thì bạn sẽ thấy các giá trị khác nhau cho set_options (là một mặt nạ bit). Đó chỉ là sự khởi đầu; Tôi sẽ đối phó ở đây và nói với bạn rằng bạn có thể xác định bộ tùy chọn nào được kích hoạt cho mỗi kế hoạch bằng cách giải nén giá trị theo phần "Đánh giá bộ tùy chọn" tại đây. Vâng, tôi thật lười biếng.

Kết luận

Có một số lý do tại sao bạn có thể thấy các kế hoạch khác nhau cho cùng một truy vấn (hoặc những gì bạn nghĩ là cùng một truy vấn). Trong hầu hết các trường hợp, bạn có thể xác định nguyên nhân khá dễ dàng; thách thức thường là biết tìm kiếm nó ngay từ đầu. Trong bài đăng tiếp theo của tôi, tôi sẽ nói về một chủ đề hơi khác:tại sao một cơ sở dữ liệu được khôi phục về một máy chủ "giống hệt nhau" có thể mang lại các kế hoạch khác nhau cho cùng một truy vấn.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. THÔNG TIN CHỨNG TỪ KHÓA NGOẠI LỆ SQL:Hướng dẫn Cơ bản, Dễ dàng cho Người mới

  2. Làm cách nào để tạo một cột duy nhất trong SQL?

  3. Cách tính căn bậc hai trong SQL

  4. Hội thảo trên web về Plan Explorer 3.0 - Mẫu và Hỏi và Đáp

  5. Số lần xem và số liệu thống kê được lập chỉ mục