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

Vấn đề Halloween - Phần 4

[Phần 1 | Phần 2 | Phần 3 | Phần 4]

Vấn đề Halloween có thể có một số ảnh hưởng quan trọng đến kế hoạch thực hiện. Trong phần cuối cùng của loạt bài này, chúng tôi xem xét các thủ thuật mà trình tối ưu hóa có thể sử dụng để tránh Sự cố Halloween khi biên dịch các kế hoạch cho các truy vấn thêm, thay đổi hoặc xóa dữ liệu.

Bối cảnh

Trong nhiều năm, một số cách tiếp cận đã được thử để tránh Vấn đề Halloween. Một kỹ thuật ban đầu là tránh xây dựng bất kỳ kế hoạch thực thi nào liên quan đến việc đọc và ghi vào các khóa của cùng một chỉ mục. Điều này không thành công lắm theo quan điểm hiệu suất, đặc biệt là vì nó thường có nghĩa là quét bảng cơ sở thay vì sử dụng chỉ mục không phân tán có chọn lọc để xác định các hàng cần thay đổi.

Cách tiếp cận thứ hai là tách biệt hoàn toàn các giai đoạn đọc và ghi của truy vấn cập nhật, bằng cách định vị đầu tiên tất cả các hàng đủ điều kiện cho thay đổi, lưu trữ chúng ở đâu đó và chỉ sau đó bắt đầu thực hiện các thay đổi. Trong SQL Server, phân tách giai đoạn đầy đủ này đạt được bằng cách đặt Bộ đệm bảng Eager hiện đã quen thuộc ở phía đầu vào của toán tử cập nhật:

Spool đọc tất cả các hàng từ đầu vào của nó và lưu trữ chúng trong tempdb ẩn bàn làm việc. Các trang của bảng công việc này có thể vẫn còn trong bộ nhớ hoặc chúng có thể yêu cầu dung lượng đĩa vật lý nếu tập hợp các hàng lớn hoặc nếu máy chủ bị áp lực bộ nhớ.

Tách giai đoạn đầy đủ có thể ít hơn lý tưởng bởi vì chúng tôi thường muốn chạy càng nhiều kế hoạch càng tốt dưới dạng đường ống, trong đó mỗi hàng được xử lý đầy đủ trước khi chuyển sang phần tiếp theo. Pipelining có nhiều lợi thế bao gồm tránh yêu cầu lưu trữ tạm thời và chỉ chạm vào mỗi hàng một lần.

Trình tối ưu hóa máy chủ SQL

SQL Server đi xa hơn nhiều so với hai kỹ thuật được mô tả cho đến nay, mặc dù nó tất nhiên bao gồm cả hai dưới dạng tùy chọn. Trình tối ưu hóa truy vấn SQL Server phát hiện các truy vấn yêu cầu Bảo vệ Halloween, xác định số lượng bảo vệ là bắt buộc và sử dụng dựa trên chi phí phân tích để tìm ra phương pháp cung cấp sự bảo vệ đó rẻ nhất.

Cách dễ nhất để hiểu khía cạnh này của Vấn đề Halloween là xem một số ví dụ. Trong các phần sau, nhiệm vụ là thêm một dải số vào bảng hiện có - nhưng chỉ những số chưa tồn tại:

CREATE TABLE dbo.Test
(
    pk      integer NOT NULL,
 
    CONSTRAINT PK_Test
        PRIMARY KEY CLUSTERED (pk)
);

5 hàng

Ví dụ đầu tiên xử lý một loạt các số từ 1 đến 5 bao gồm:

INSERT dbo.Test (pk)
SELECT Num.n 
FROM dbo.Numbers AS Num
WHERE
    Num.n BETWEEN 1 AND 5
    AND NOT EXISTS 
    (
        SELECT NULL
        FROM dbo.Test AS t 
        WHERE t.pk = Num.n
    );

Vì truy vấn này đọc và ghi vào các khóa của cùng một chỉ mục trên bảng Kiểm tra, nên kế hoạch thực thi yêu cầu Bảo vệ Halloween. Trong trường hợp này, trình tối ưu hóa sử dụng phân tách pha đầy đủ bằng Bộ đệm bảng Eager:

50 hàng

Với năm hàng hiện trong bảng Kiểm tra, chúng tôi chạy lại cùng một truy vấn, thay đổi WHERE mệnh đề để xử lý các số từ 1 đến 50 bao gồm :

Kế hoạch này cung cấp sự bảo vệ chính xác chống lại Sự cố Halloween, nhưng nó không có Bộ đệm Bảng Háo hức. Trình tối ưu hóa nhận ra rằng toán tử tham gia Hash Match đang chặn trên đầu vào xây dựng của nó; tất cả các hàng được đọc vào một bảng băm trước khi người vận hành bắt đầu quá trình đối sánh bằng cách sử dụng các hàng từ đầu vào thăm dò. Do đó, kế hoạch này cung cấp tính năng tách pha (chỉ dành cho bảng Thử nghiệm) một cách tự nhiên mà không cần ống đệm.

Trình tối ưu hóa đã chọn kế hoạch tham gia Đối sánh băm thay vì tham gia Vòng lặp lồng nhau được thấy trong kế hoạch 5 hàng vì lý do dựa trên chi phí. Kế hoạch Đối sánh băm 50 hàng có tổng chi phí ước tính là 0,0347345 các đơn vị. Chúng tôi có thể buộc kế hoạch Vòng lặp lồng nhau được sử dụng trước đó với gợi ý để xem tại sao trình tối ưu hóa không chọn các vòng lặp lồng nhau:

Kế hoạch này có chi phí ước tính là 0,0379063 các đơn vị bao gồm ống chỉ, nhiều hơn một chút so với gói Hash Match.

500 hàng

Với 50 hàng hiện trong bảng Kiểm tra, chúng tôi tăng thêm phạm vi số lên 500 :

Lần này, trình tối ưu hóa chọn một Kết hợp Hợp nhất và một lần nữa không có Bộ đệm Bảng Eager. Toán tử Sắp xếp cung cấp sự phân chia giai đoạn cần thiết trong kế hoạch này. Nó hoàn toàn sử dụng đầu vào trước khi trả về hàng đầu tiên (sắp xếp không thể biết hàng nào sắp xếp trước cho đến khi tất cả các hàng được nhìn thấy). Trình tối ưu hóa đã quyết định rằng sắp xếp 50 các hàng từ bảng Kiểm tra sẽ rẻ hơn so với dòng háo hức 450 hàng ngay trước toán tử cập nhật.

Gói sắp xếp cộng với kết hợp hợp nhất có chi phí ước tính là 0,0362708 các đơn vị. Các lựa chọn thay thế cho kế hoạch Kết hợp băm và Vòng lặp lồng nhau ra mắt ở mức 0,0385677 đơn vị và 0,112433 đơn vị tương ứng.

Có điều gì đó kỳ lạ về Sắp xếp

Nếu bạn đang chạy các ví dụ này cho chính mình, bạn có thể nhận thấy điều gì đó kỳ lạ về ví dụ cuối cùng đó, đặc biệt nếu bạn đã xem các mẹo công cụ Plan Explorer cho bảng Kiểm tra Tìm kiếm và Sắp xếp:

The Seek tạo ra một đặt hàng luồng pk các giá trị, vậy điểm sắp xếp trên cùng một cột ngay sau đó là gì? Để trả lời câu hỏi (rất hợp lý) đó, chúng ta bắt đầu bằng cách chỉ xem xét SELECT phần của INSERT truy vấn:

SELECT Num.n 
FROM dbo.Numbers AS Num
WHERE
    Num.n BETWEEN 1 AND 500
    AND NOT EXISTS 
    (
        SELECT 1
        FROM dbo.Test AS t 
        WHERE t.pk = Num.n
    )
ORDER BY
    Num.n;

Truy vấn này tạo ra kế hoạch thực thi bên dưới (có hoặc không có ORDER BY Tôi đã thêm để giải quyết một số phản đối kỹ thuật nhất định mà bạn có thể có):

Chú ý thiếu toán tử Sắp xếp. Vậy tại sao INSERT kế hoạch bao gồm một Sắp xếp? Đơn giản là để tránh vấn đề Halloween. Trình tối ưu hóa đã xem xét rằng thực hiện sắp xếp dư thừa (với tính năng tách pha tích hợp) là cách rẻ nhất để thực hiện truy vấn và đảm bảo kết quả chính xác. Thông minh.

Các cấp độ và thuộc tính Bảo vệ Halloween

Trình tối ưu hóa SQL Server có các tính năng cụ thể cho phép nó suy luận về mức độ Bảo vệ Halloween (HP) cần thiết tại mỗi thời điểm trong kế hoạch truy vấn và tác động chi tiết mà mỗi toán tử có. Các tính năng bổ sung này được kết hợp vào cùng một khung thuộc tính mà trình tối ưu hóa sử dụng để theo dõi hàng trăm bit thông tin quan trọng khác trong các hoạt động tìm kiếm của nó.

Mỗi nhà điều hành có một yêu cầu Thuộc tính HP và đã giao Tài sản HP. bắt buộc thuộc tính cho biết mức HP cần thiết tại thời điểm đó trong cây để có kết quả chính xác. Đã giao thuộc tính phản ánh HP do nhà điều hành hiện tại cung cấp và tích lũy Hiệu ứng HP được cung cấp bởi cây con của nó.

Trình tối ưu hóa chứa logic để xác định cách mỗi toán tử vật lý (ví dụ:Vô hướng tính toán) ảnh hưởng đến mức HP. Bằng cách khám phá một loạt các lựa chọn thay thế gói và từ chối các kế hoạch trong đó HP đã giao ít hơn HP yêu cầu tại nhà điều hành cập nhật, trình tối ưu hóa có một cách linh hoạt để tìm các kế hoạch hiệu quả, chính xác mà không phải lúc nào cũng yêu cầu Bộ đệm Bảng Eager.

Thay đổi kế hoạch cho Bảo vệ Halloween

Chúng tôi đã thấy trình tối ưu hóa thêm một loại dư thừa cho Bảo vệ Halloween trong ví dụ Kết hợp tham gia trước đó. Làm thế nào chúng tôi có thể chắc chắn rằng điều này hiệu quả hơn so với một ống chỉ thư bảng Eager đơn giản? Và làm thế nào chúng tôi có thể biết những tính năng nào của gói cập nhật chỉ dành cho Bảo vệ Halloween?

Cả hai câu hỏi đều có thể được trả lời (tự nhiên trong môi trường thử nghiệm) bằng cách sử dụng cờ theo dõi không có tài liệu 8692 , điều này buộc trình tối ưu hóa phải sử dụng Bộ đệm Bảng Eager để Bảo vệ Halloween. Nhớ lại rằng kế hoạch Kết hợp hợp nhất với sắp xếp dự phòng có chi phí ước tính là 0,0362708 đơn vị tối ưu hóa ma thuật. Chúng ta có thể so sánh điều đó với giải pháp thay thế Eager Table Spool bằng cách biên dịch lại truy vấn có bật cờ theo dõi 8692:

INSERT dbo.Test (pk)
SELECT Num.n 
FROM dbo.Numbers AS Num
WHERE
    Num.n BETWEEN 1 AND 500
    AND NOT EXISTS 
    (
        SELECT 1
        FROM dbo.Test AS t 
        WHERE t.pk = Num.n
    )
OPTION (QUERYTRACEON 8692);

Gói Eager Spool có chi phí ước tính là 0,0378719 đơn vị (tăng từ 0,0362708 với sắp xếp dư thừa). Sự khác biệt về chi phí được hiển thị ở đây là không đáng kể do tính chất nhỏ của nhiệm vụ và kích thước nhỏ của các hàng. Các truy vấn cập nhật trong thế giới thực với các cây phức tạp và số lượng hàng lớn hơn thường tạo ra các kế hoạch hiệu quả hơn nhiều nhờ khả năng suy nghĩ sâu sắc về Bảo vệ Halloween của trình tối ưu hóa SQL Server.

Các tùy chọn không phải ống đệm khác

Định vị một nhà điều hành chặn một cách tối ưu trong một kế hoạch không phải là chiến lược duy nhất mở cho trình tối ưu hóa để giảm thiểu chi phí cung cấp bảo vệ chống lại Vấn đề Halloween. Nó cũng có thể giải thích về phạm vi giá trị đang được xử lý, như ví dụ sau minh họa:

CREATE TABLE #Test
(
    pk          integer IDENTITY PRIMARY KEY,
    some_value  integer
);
 
CREATE INDEX i ON #Test (some_value);
 
-- Pretend the table has lots of data in it
UPDATE STATISTICS #Test
WITH ROWCOUNT = 123456, PAGECOUNT = 1234;
 
UPDATE #Test
SET some_value = 10
WHERE some_value = 5;

Kế hoạch thực thi cho thấy không cần đến Bảo vệ Halloween, mặc dù thực tế là chúng tôi đang đọc và cập nhật các khóa của một chỉ mục chung:

Trình tối ưu hóa có thể thấy rằng việc thay đổi ‘some_value’ từ 5 thành 10 không bao giờ có thể khiến Index Seek nhìn thấy hàng cập nhật lần thứ hai (chỉ tìm kiếm các hàng có some_value là 5). Suy luận này chỉ có thể thực hiện được khi các giá trị chữ được sử dụng trong truy vấn hoặc khi truy vấn chỉ định OPTION (RECOMPILE) , cho phép trình tối ưu hóa đánh giá các giá trị của các tham số cho kế hoạch thực thi một lần.

Ngay cả với các giá trị chữ trong truy vấn, trình tối ưu hóa có thể bị ngăn áp dụng logic này nếu tùy chọn cơ sở dữ liệu FORCED PARAMETERIZATION ON . Trong trường hợp đó, các giá trị chữ trong truy vấn được thay thế bằng các tham số và trình tối ưu hóa không còn có thể chắc chắn rằng Bảo vệ Halloween không được yêu cầu (hoặc sẽ không được yêu cầu khi kế hoạch được sử dụng lại với các giá trị tham số khác nhau):

Trong trường hợp bạn đang thắc mắc điều gì sẽ xảy ra nếu FORCED PARAMETERIZATION được bật truy vấn chỉ định OPTION (RECOMPILE) , câu trả lời là trình tối ưu hóa soạn một kế hoạch cho các giá trị được đánh hơi và do đó có thể áp dụng tối ưu hóa. Như mọi khi với OPTION (RECOMPILE) , kế hoạch truy vấn giá trị cụ thể không được lưu vào bộ nhớ đệm để sử dụng lại.

Trên cùng

Ví dụ cuối cùng này cho thấy cách Top nhà điều hành có thể loại bỏ nhu cầu Bảo vệ Halloween:

UPDATE TOP (1) t
SET some_value += 1
FROM #Test AS t
WHERE some_value <= 10;

Không cần bảo vệ vì chúng tôi chỉ cập nhật một hàng. Giá trị cập nhật không thể tìm thấy bởi Index Seek, bởi vì quy trình xử lý dừng ngay sau khi hàng đầu tiên được cập nhật. Một lần nữa, tối ưu hóa này chỉ có thể được áp dụng nếu một giá trị chữ không đổi được sử dụng trong TOP hoặc nếu một biến trả về giá trị ‘1’ được phát hiện bằng cách sử dụng OPTION (RECOMPILE) .

Nếu chúng tôi thay đổi TOP (1) trong truy vấn đến TOP (2) , trình tối ưu hóa chọn Quét chỉ mục theo cụm thay vì Tìm kiếm chỉ mục:

Chúng tôi không cập nhật các khóa của chỉ mục theo nhóm, vì vậy kế hoạch này không yêu cầu Bảo vệ Halloween. Buộc sử dụng chỉ mục không phân biệt với gợi ý trong TOP (2) truy vấn làm cho chi phí bảo vệ rõ ràng:

Trình tối ưu hóa ước tính Quét chỉ mục theo cụm sẽ rẻ hơn kế hoạch này (với tính năng Bảo vệ Halloween bổ sung).

Tỷ lệ cược và kết thúc

Có một vài điểm khác mà tôi muốn làm về Bảo vệ Halloween mà chưa tìm thấy vị trí tự nhiên trong loạt phim trước đây. Đầu tiên là câu hỏi về Bảo vệ Halloween khi mức cách ly lập phiên bản hàng được sử dụng.

Tạo phiên bản hàng

SQL Server cung cấp hai cấp độ cách ly, READ COMMITTED SNAPSHOTSNAPSHOT ISOLATION sử dụng cửa hàng phiên bản trong tempdb để cung cấp chế độ xem nhất quán ở cấp độ giao dịch hoặc tuyên bố của cơ sở dữ liệu. SQL Server có thể tránh Halloween Protection hoàn toàn theo các mức cách ly này, vì kho lưu trữ phiên bản có thể cung cấp dữ liệu không bị ảnh hưởng bởi bất kỳ thay đổi nào mà câu lệnh hiện đang thực thi có thể đã thực hiện cho đến nay. Ý tưởng này hiện không được triển khai trong phiên bản SQL Server đã phát hành, mặc dù Microsoft đã nộp bằng sáng chế mô tả cách thức hoạt động của nó, vì vậy có lẽ một phiên bản trong tương lai sẽ kết hợp công nghệ này.

Hàng đống và Bản ghi Chuyển tiếp

Nếu bạn đã quen thuộc với phần bên trong của cấu trúc heap, bạn có thể tự hỏi liệu Sự cố Halloween cụ thể có thể xảy ra khi các bản ghi được chuyển tiếp được tạo trong một bảng heap hay không. Trong trường hợp điều này là mới đối với bạn, một bản ghi đống sẽ được chuyển tiếp nếu một hàng hiện có được cập nhật để nó không còn phù hợp với trang dữ liệu ban đầu. Công cụ này để lại một cuống chuyển tiếp và di chuyển bản ghi đã mở rộng sang một trang khác.

Sự cố có thể xảy ra nếu một kế hoạch chứa quét đống cập nhật một bản ghi để nó được chuyển tiếp. Quét đống có thể gặp lại hàng khi vị trí quét đến trang có bản ghi được chuyển tiếp. Trong SQL Server, vấn đề này được tránh vì Công cụ lưu trữ đảm bảo luôn tuân theo các con trỏ chuyển tiếp ngay lập tức. Nếu quá trình quét gặp một bản ghi đã được chuyển tiếp, nó sẽ bỏ qua nó. Với biện pháp bảo vệ này, trình tối ưu hóa truy vấn không phải lo lắng về trường hợp này.

Hàm vô hướng SCHEMABINDING và T-SQL

Có rất ít trường hợp sử dụng hàm vô hướng T-SQL là một ý tưởng hay, nhưng nếu bạn phải sử dụng hàm này, bạn nên biết về tác dụng quan trọng của nó đối với Bảo vệ Halloween. Trừ khi một hàm vô hướng được khai báo với SCHEMABINDING tùy chọn, SQL Server giả định hàm truy cập các bảng. Để minh họa, hãy xem xét hàm vô hướng T-SQL đơn giản bên dưới:

CREATE FUNCTION dbo.ReturnInput
(
    @value integer
)
RETURNS integer
AS
BEGIN
	RETURN @value;
END;

Chức năng này không truy cập bất kỳ bảng nào; trong thực tế, nó không làm gì ngoại trừ trả về giá trị tham số được truyền cho nó. Bây giờ hãy xem INSERT sau truy vấn:

DECLARE @T AS TABLE (ProductID integer PRIMARY KEY);
 
INSERT @T (ProductID)
SELECT p.ProductID
FROM AdventureWorks2012.Production.Product AS p;

Kế hoạch thực hiện chính xác như chúng tôi mong đợi, không cần Bảo vệ Halloween:

Tuy nhiên, việc thêm chức năng không làm gì của chúng tôi có một tác động đáng kể:

DECLARE @T AS TABLE (ProductID integer PRIMARY KEY);
 
INSERT @T (ProductID)
SELECT dbo.ReturnInput(p.ProductID)
FROM AdventureWorks2012.Production.Product AS p;

Kế hoạch thực hiện hiện bao gồm một Bộ đệm Bảng Háo hức để Bảo vệ Lễ hội Halloween. SQL Server giả định hàm truy cập dữ liệu, có thể bao gồm việc đọc lại từ bảng Sản phẩm. Như bạn có thể nhớ lại, một INSERT kế hoạch có chứa tham chiếu đến bảng mục tiêu ở phía đọc của kế hoạch yêu cầu Bảo vệ Halloween đầy đủ và theo như trình tối ưu hóa biết, đó có thể là trường hợp ở đây.

Thêm SCHEMABINDING tùy chọn định nghĩa hàm có nghĩa là SQL Server kiểm tra phần thân của hàm để xác định nó truy cập vào bảng nào. Nó không tìm thấy quyền truy cập như vậy và do đó không thêm bất kỳ Bảo vệ Halloween nào:

ALTER FUNCTION dbo.ReturnInput
(
    @value integer
)
RETURNS integer
WITH SCHEMABINDING
AS
BEGIN
	RETURN @value;
END;
GO
DECLARE @T AS TABLE (ProductID int PRIMARY KEY);
 
INSERT @T (ProductID)
SELECT p.ProductID
FROM AdventureWorks2012.Production.Product AS p;

Sự cố này với các hàm vô hướng T-SQL ảnh hưởng đến tất cả các truy vấn cập nhật - INSERT , UPDATE , DELETEMERGE . Việc biết khi nào bạn đang gặp phải vấn đề này càng khó khăn hơn vì Bảo vệ Halloween không cần thiết sẽ không phải lúc nào cũng hiển thị dưới dạng Bộ đệm bảng Eager bổ sung và các lệnh gọi hàm vô hướng có thể bị ẩn trong các dạng xem hoặc định nghĩa cột được tính toán, chẳng hạn.

[Phần 1 | Phần 2 | Phần 3 | Phần 4]


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Xuân Hội nhập là gì?

  2. Cách tạo khóa chính trong SQL

  3. Truy xuất thông báo lỗi hoàn chỉnh trong isql

  4. Tác dụng phụ không mong muốn của việc thêm chỉ mục được lọc

  5. Cách khai báo ngoại lệ do người dùng xác định bằng PRAGMA EXCEPTION_INIT