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

Mục tiêu hàng, Phần 4:Mô hình chống tham gia chống

Bài đăng này là một phần của loạt bài về mục tiêu hàng. Bạn có thể tìm thấy các phần khác tại đây:

  • Phần 1:Thiết lập và Xác định Mục tiêu Hàng
  • Phần 2:Bán kết
  • Phần 3:Chống tham gia

Áp dụng Chống tham gia với nhà điều hành Hàng đầu

Bạn thường sẽ thấy toán tử Top (1) bên trong trong áp dụng kết hợp chống các kế hoạch thực hiện. Ví dụ:sử dụng cơ sở dữ liệu AdventureWorks:

 CHỌN P.ProductID TỪ SẢN XUẤT. SẢN PHẨM NHƯ PWHERE KHÔNG TỒN TẠI (CHỌN 1 TỪ SẢN XUẤT.TransactionHistory AS TH WHERE TH.ProductID =P.ProductID); 

Kế hoạch hiển thị toán tử Top (1) ở phía bên trong của ứng dụng (tham chiếu bên ngoài) chống tham gia:

Toán tử hàng đầu này hoàn toàn dư thừa . Nó không bắt buộc đối với tính đúng đắn, hiệu quả hoặc để đảm bảo mục tiêu hàng được đặt.

Toán tử áp dụng chống nối sẽ ngừng kiểm tra các hàng ở phía bên trong (đối với lần lặp hiện tại) ngay sau khi một hàng được nhìn thấy tại phép nối. Hoàn toàn có thể tạo ra một kế hoạch chống tham gia áp dụng mà không cần Top. Vậy tại sao lại có Nhà điều hành hàng đầu trong kế hoạch này?

Nguồn của toán tử hàng đầu

Để hiểu toán tử Top vô nghĩa này đến từ đâu, chúng ta cần làm theo các bước chính được thực hiện trong quá trình biên dịch và tối ưu hóa truy vấn mẫu của chúng ta.

Như thường lệ, truy vấn đầu tiên được phân tích cú pháp thành một cây. Điều này có một toán tử logic 'không tồn tại' với một truy vấn con, phù hợp chặt chẽ với dạng viết của truy vấn trong trường hợp này:

Truy vấn con không tồn tại được hủy đăng ký vào một liên kết chống áp dụng:

Sau đó, điều này tiếp tục được chuyển đổi thành một liên kết chống bán trái hợp lý. Cây kết quả được chuyển đến tối ưu hóa dựa trên chi phí trông như thế này:

Khám phá đầu tiên được thực hiện bởi trình tối ưu hóa dựa trên chi phí là giới thiệu sự khác biệt hợp lý hoạt động trên đầu vào chống nối thấp hơn, để tạo ra các giá trị duy nhất cho khóa chống nối. Ý tưởng chung là thay vì thử nghiệm các giá trị trùng lặp tại phép nối, kế hoạch có thể có lợi từ việc nhóm các giá trị đó lên trước.

Quy tắc thăm dò có trách nhiệm được gọi là LASJNtoLASJNonDist (left anti semi join để left anti semi join trên khác biệt). Chưa có triển khai vật lý hoặc chi phí nào được thực hiện, vì vậy đây chỉ là trình tối ưu hóa khám phá sự tương đương hợp lý, dựa trên sự hiện diện của ProductID trùng lặp các giá trị. Cây mới với thao tác nhóm được thêm vào được hiển thị bên dưới:

Phép chuyển đổi logic tiếp theo được xem xét là viết lại phép nối dưới dạng áp dụng . Điều này được khám phá bằng cách sử dụng quy tắc LASJNtoApply (trái phép nối bán chống để áp dụng với lựa chọn quan hệ). Như đã đề cập trước đó trong loạt bài, chuyển đổi trước đó từ áp dụng sang nối là cho phép các phép biến đổi hoạt động cụ thể trên các phép nối. Luôn có thể viết lại một phép nối dưới dạng đơn đăng ký, do đó, điều này mở rộng phạm vi tối ưu hóa có sẵn.

Bây giờ, trình tối ưu hóa không luôn luôn coi việc viết lại áp dụng là một phần của tối ưu hóa dựa trên chi phí. Cần phải có một cái gì đó trong cây logic để làm cho nó đáng giá khi đẩy vị từ nối xuống phía bên trong. Thông thường, đây sẽ là sự tồn tại của một chỉ số phù hợp, nhưng có những mục tiêu đầy hứa hẹn khác. Trong trường hợp này, nó là khóa logic trên ProductID được tạo bởi hoạt động tổng hợp.

Kết quả của quy tắc này là sự kết hợp chống có tương quan với sự lựa chọn ở phía bên trong:

Tiếp theo, trình tối ưu hóa xem xét việc di chuyển lựa chọn quan hệ (vị từ kết hợp tương quan) xuống phía bên trong, qua phần riêng biệt (nhóm theo tổng hợp) đã được trình tối ưu hóa giới thiệu trước đó. Điều này được thực hiện theo quy tắc SelOnGbAgg , di chuyển càng nhiều lựa chọn (vị từ) qua một nhóm phù hợp theo tổng thể càng tốt (một phần của lựa chọn có thể bị bỏ lại). Hoạt động này giúp đẩy các lựa chọn càng gần các toán tử truy cập dữ liệu cấp lá càng tốt, để loại bỏ các hàng sớm hơn và làm cho việc đối sánh chỉ mục sau này dễ dàng hơn.

Trong trường hợp này, bộ lọc nằm trên cùng một cột với thao tác nhóm, vì vậy phép biến đổi là hợp lệ. Điều này dẫn đến toàn bộ lựa chọn được đẩy vào tổng thể:

Hoạt động quan tâm cuối cùng được thực hiện bởi quy tắc GbAggToConstScanOrTop . Biến đổi này có vẻ như thay thế một nhóm được tổng hợp bằng Quét liên tục hoặc Trên cùng hoạt động logic. Quy tắc này phù hợp với cây của chúng tôi vì cột nhóm là không đổi đối với mỗi hàng đi qua vùng chọn được đẩy xuống. Tất cả các hàng được đảm bảo có cùng một ProductID . Nhóm trên một giá trị sẽ luôn tạo ra một hàng. Do đó, nó là hợp lệ để chuyển đổi tổng hợp thành Top (1). Vì vậy, đây là nơi xuất phát đỉnh.

Thực hiện và chi phí

Trình tối ưu hóa hiện chạy một loạt các quy tắc triển khai để tìm các toán tử vật lý cho từng lựa chọn thay thế logic đầy hứa hẹn mà nó đã xem xét cho đến nay (được lưu trữ hiệu quả trong cấu trúc bản ghi nhớ). Băm và hợp nhất các tùy chọn vật lý chống tham gia xuất phát từ cây ban đầu với tổng hợp đã giới thiệu (lịch sự của quy tắc LASJNtoLASJNonDist nhớ). Ứng dụng cần thêm một chút công việc để tạo đỉnh vật lý và khớp lựa chọn với tìm kiếm chỉ mục.

Tham gia chống băm tốt nhất giải pháp được tìm thấy có giá là 0,362143 đơn vị:

Hợp nhất chống tham gia tốt nhất giải pháp có ở 0,353479 đơn vị (rẻ hơn một chút):

Áp dụng chống tham gia chi phí 0,091823 đơn vị (rẻ nhất với biên độ rộng):

Người đọc nhạy bén có thể nhận thấy số hàng ở phía bên trong của liên kết chống áp dụng (504) khác với ảnh chụp màn hình trước đó của cùng một kế hoạch. Điều này là do đây là một kế hoạch ước tính, trong khi kế hoạch trước đó là sau khi thực hiện. Khi kế hoạch này được thực thi, chỉ có tổng cộng 441 hàng được tìm thấy ở phía bên trong qua tất cả các lần lặp. Điều này làm nổi bật một trong những khó khăn hiển thị khi áp dụng kế hoạch kết hợp bán / chống:Ước tính tối ưu hóa tối thiểu là một hàng, nhưng kết nối bán hoặc chống nối sẽ luôn định vị một hàng hoặc không có hàng trên mỗi lần lặp. 504 hàng hiển thị ở trên đại diện cho 1 hàng trên mỗi 504 lần lặp. Để làm cho các con số khớp với nhau, ước tính sẽ cần phải là 441/504 =0,875 hàng mỗi lần, điều này có thể sẽ khiến mọi người nhầm lẫn nhiều.

Dù sao, kế hoạch ở trên đủ 'may mắn' để đủ điều kiện cho một mục tiêu liên tiếp ở phía bên trong của áp dụng chống tham gia vì hai lý do:

  1. Liên kết chống được chuyển đổi từ một liên kết thành một áp dụng trong trình tối ưu hóa dựa trên chi phí. Điều này đặt mục tiêu hàng (như đã thiết lập trong phần ba).
  2. Toán tử Trên cùng (1) cũng đặt mục tiêu hàng trên cây con của nó.

Bản thân toán tử Hàng đầu không có mục tiêu hàng (từ trường hợp áp dụng) vì mục tiêu hàng là 1 sẽ không nhỏ hơn so với ước tính thông thường, cũng là 1 hàng (Thẻ =1 cho PhyOp_Top bên dưới):

Mô hình chống tham gia chống tham gia

Hình dạng sơ đồ chung sau đây là hình dạng mà tôi coi là hình mẫu chống:

Không phải mọi kế hoạch thực thi có chứa một phép nối chống áp dụng với toán tử Top (1) ở phía bên trong của nó sẽ có vấn đề. Tuy nhiên, đó là một mô hình để nhận ra và một mô hình hầu như luôn luôn đòi hỏi phải điều tra thêm.

Bốn yếu tố chính cần chú ý là:

  • Một vòng lặp lồng nhau có tương quan ( áp dụng ) chống tham gia
  • Đ ầu (1) nhà điều hành ngay lập tức ở phía bên trong
  • Một số lượng đáng kể các hàng ở đầu vào bên ngoài (vì vậy, phía bên trong sẽ được chạy nhiều lần)
  • Đ có thể đắt tiền cây con bên dưới Đầu trang

Cây con "$$$" là cây con có khả năng đắt tiền khi chạy . Điều này có thể khó nhận ra. Nếu chúng ta may mắn, sẽ có một cái gì đó hiển nhiên như quét toàn bộ bảng hoặc chỉ mục. Trong những trường hợp khó khăn hơn, cây con thoạt nhìn sẽ hoàn toàn vô tội, nhưng lại ẩn chứa điều gì đó đắt giá khi nhìn kỹ hơn. Để đưa ra một ví dụ khá phổ biến, bạn có thể thấy Tìm kiếm chỉ mục được mong đợi trả về một số lượng nhỏ hàng, nhưng chứa một vị từ dư đắt tiền kiểm tra một số lượng rất lớn hàng để tìm ra một số ít đủ điều kiện.

Ví dụ mã AdventureWorks trước đó không có cây con "có thể đắt". Tìm kiếm Chỉ mục (không có vị từ dư) sẽ là một phương pháp truy cập tối ưu bất kể các cân nhắc về mục tiêu hàng. Đây là một điểm quan trọng:cung cấp trình tối ưu hóa luôn hiệu quả đường dẫn truy cập dữ liệu ở phía bên trong của phép nối tương quan luôn là một ý tưởng hay. Điều này càng đúng hơn khi ứng dụng đang chạy ở chế độ chống nối với toán tử Top (1) ở phía bên trong.

Bây giờ chúng ta hãy xem xét một ví dụ có hiệu suất thời gian chạy khá tệ do mô hình chống này.

Ví dụ

Tập lệnh sau tạo hai bảng tạm thời trong đống. Đầu tiên có 500 hàng bao gồm các số nguyên từ 1 đến 500. Bảng thứ hai có 500 bản sao của mỗi hàng trong bảng đầu tiên, với tổng số 250.000 hàng. Cả hai bảng đều sử dụng sql_variant kiểu dữ liệu.

 DROP TABLE NẾU TỒN TẠI # T1, # T2; TẠO BẢNG # T1 (c1 sql_variant NOT NULL); TẠO BẢNG # T2 (c1 sql_variant NOT NULL); - Các số từ 1 đến 500 1 AND SV.number <=500; - 500 bản sao của mỗi hàng trong bảng # T1INSERT # T2 (c1) SELECT T1.c1FROM # T1 AS T1CROSS JOIN # T1 AS T2; - Đảm bảo chúng tôi có thông tin thống kê tốt nhất có thể 

Hiệu suất

Bây giờ chúng tôi chạy một truy vấn tìm kiếm các hàng trong bảng nhỏ hơn không có trong bảng lớn hơn (tất nhiên là không có hàng nào):

 CHỌN T1.c1 TỪ # T1 NHƯ T1 KHÔNG TỒN TẠI (CHỌN 1 TỪ # T2 NHƯ T2 TRONG ĐÓ T2.c1 =T1.c1); 

Truy vấn này chạy trong khoảng 20 giây , một thời gian dài khủng khiếp để so sánh 500 hàng với 250.000. Kế hoạch ước tính SSMS khiến chúng ta khó hiểu tại sao hiệu suất có thể kém như vậy:

Người quan sát cần lưu ý rằng các kế hoạch ước tính SSMS hiển thị các ước tính bên trong mỗi lần lặp của phép nối vòng lặp lồng nhau. Thật khó hiểu, kế hoạch thực tế SSMS hiển thị số hàng trên tất cả các lần lặp lại . Plan Explorer tự động thực hiện các phép tính đơn giản cần thiết cho các kế hoạch ước tính cũng như hiển thị tổng số hàng dự kiến:

Mặc dù vậy, hiệu suất thời gian chạy kém hơn nhiều so với ước tính. Kế hoạch thực hiện sau khi thực hiện (thực tế) là:

Lưu ý Bộ lọc riêng biệt, thường sẽ được đẩy xuống bản quét như một vị từ còn lại. Đây là lý do sử dụng sql_variant loại dữ liệu; nó ngăn không cho đẩy vị từ, điều này làm cho số lượng lớn các hàng từ quá trình quét dễ dàng nhìn thấy hơn.

Phân tích

Lý do cho sự khác biệt là do cách trình tối ưu hóa ước tính số hàng mà nó sẽ cần đọc từ Bảng quét để đáp ứng mục tiêu một hàng được đặt tại Bộ lọc. Giả định đơn giản là các giá trị được phân phối đồng đều trong bảng, do đó, để gặp 1 trong 500 giá trị duy nhất hiện tại, SQL Server sẽ cần đọc 250.000 / 500 =500 hàng. Hơn 500 lần lặp, có tới 250.000 hàng.

Giả định về tính đồng nhất của trình tối ưu hóa là một giả định chung, nhưng nó không hoạt động tốt ở đây. Bạn có thể đọc thêm về điều này trong Yêu cầu mục tiêu hàng của Joe Obbish và bỏ phiếu cho đề xuất của anh ấy trên diễn đàn phản hồi thay thế Connect tại Sử dụng nhiều hơn mật độ để chi phí quét ở phía bên trong của vòng lặp lồng nhau với TOP.

Quan điểm của tôi về khía cạnh cụ thể này là trình tối ưu hóa phải nhanh chóng lùi khỏi giả định về tính đồng nhất đơn giản khi toán tử ở phía bên trong của phép nối các vòng lồng nhau (tức là số tua ước tính cộng với số tua lại lớn hơn một). Có một điều giả sử rằng chúng ta cần đọc 500 hàng để tìm thấy sự trùng khớp trong lần lặp đầu tiên của vòng lặp. Giả sử điều này trên mỗi lần lặp lại có vẻ không chính xác lắm; nó có nghĩa là 500 hàng đầu tiên gặp phải phải chứa một trong mỗi giá trị riêng biệt. Điều này rất khó xảy ra trong thực tế.

Một loạt các sự kiện đáng tiếc

Bất kể cách tính phí của các toán tử Hàng đầu lặp lại như thế nào, đối với tôi, có vẻ như toàn bộ tình huống này nên được tránh ngay từ đầu . Nhớ lại cách tạo ra Top trong kế hoạch này:

  • Trình tối ưu hoá đã giới thiệu một tổng hợp riêng biệt bên trong như một cách tối ưu hoá hiệu suất .
  • Tổng hợp này cung cấp một khóa trên cột kết hợp theo định nghĩa (nó tạo ra tính duy nhất).
  • Khóa được xây dựng này cung cấp mục tiêu cho việc chuyển đổi từ kết hợp thành áp dụng.
  • Vị từ (lựa chọn) được liên kết với đơn đăng ký được đẩy xuống dưới tổng thể.
  • Tổng hợp hiện được đảm bảo hoạt động trên một giá trị riêng biệt duy nhất cho mỗi lần lặp (vì nó là một giá trị tương quan).
  • Tổng hợp được thay thế bằng Top (1).

Tất cả các biến đổi này có giá trị riêng lẻ. Chúng là một phần của các hoạt động bình thường của trình tối ưu hóa khi nó tìm kiếm một kế hoạch thực thi hợp lý. Thật không may, kết quả ở đây là tổng hợp suy đoán được đưa ra bởi trình tối ưu hóa cuối cùng được chuyển thành Hàng đầu (1) với mục tiêu hàng được liên kết . Mục tiêu hàng dẫn đến chi phí không chính xác dựa trên giả định về tính đồng nhất và sau đó dẫn đến việc lựa chọn một kế hoạch có khả năng hoạt động không tốt.

Bây giờ, người ta có thể phản đối rằng dù sao thì áp dụng chống nối sẽ có một mục tiêu hàng - không có trình tự chuyển đổi ở trên. Đối số ngược lại là trình tối ưu hóa sẽ không xem xét chuyển đổi từ chống tham gia thành áp dụng chống tham gia (đặt mục tiêu hàng) mà không có tổng hợp do trình tối ưu hóa giới thiệu đưa ra LASJNtoApply quy tắc một cái gì đó để ràng buộc. Ngoài ra, chúng tôi đã thấy (trong phần ba) rằng nếu tham gia chống đã nhập tối ưu hóa dựa trên chi phí dưới dạng áp dụng (thay vì tham gia), sẽ lại có không có mục tiêu hàng .

Nói tóm lại, mục tiêu hàng trong kế hoạch cuối cùng là hoàn toàn giả tạo và không có cơ sở trong đặc tả truy vấn ban đầu. Vấn đề với mục tiêu Hàng đầu và hàng là tác dụng phụ của khía cạnh cơ bản hơn này.

Giải pháp thay thế

Có rất nhiều giải pháp tiềm năng cho vấn đề này. Loại bỏ bất kỳ bước nào trong trình tự tối ưu hóa ở trên sẽ đảm bảo trình tối ưu hóa không tạo ra triển khai áp dụng chống nối với chi phí giảm đáng kể (và giả tạo). Hy vọng rằng sự cố này sẽ sớm được giải quyết trong SQL Server.

Trong khi chờ đợi, lời khuyên của tôi là hãy để ý đến mô hình chống tham gia chống. Đảm bảo mặt bên trong của kết nối chống áp dụng luôn có đường dẫn truy cập hiệu quả cho tất cả các điều kiện thời gian chạy. Nếu điều này không thể thực hiện được, bạn có thể cần sử dụng gợi ý, tắt mục tiêu hàng, sử dụng hướng dẫn kế hoạch hoặc buộc kế hoạch lưu trữ truy vấn để có được hiệu suất ổn định từ các truy vấn chống tham gia.

Tóm tắt loạt bài

Chúng tôi đã đề cập rất nhiều điều trong bốn phần, vì vậy đây là bản tóm tắt cấp cao:

  1. Phần 1 - Thiết lập và Xác định Mục tiêu Hàng
    • Cú pháp truy vấn không xác định sự hiện diện hay vắng mặt của một mục tiêu hàng.
    • Mục tiêu hàng chỉ được đặt khi mục tiêu nhỏ hơn ước tính thông thường.
    • Các toán tử hàng đầu vật lý (bao gồm cả những toán tử được giới thiệu bởi trình tối ưu hóa) thêm mục tiêu hàng vào cây con của chúng.
    • Một FAST hoặc SET ROWCOUNT câu lệnh đặt mục tiêu hàng ở gốc của kế hoạch.
    • Bán tham gia và chống tham gia có thể thêm một mục tiêu hàng.
    • SQL Server 2017 CU3 thêm thuộc tính showplan Ước tínhRowsWithoutRowGoal cho các toán tử bị ảnh hưởng bởi mục tiêu hàng
    • Thông tin mục tiêu hàng có thể được hiển thị bằng cờ theo dõi không có tài liệu 8607 và 8612.
  2. Phần 2 - Bán kết
    • Không thể biểu thị một kết nối bán trực tiếp trong T-SQL, vì vậy chúng tôi sử dụng cú pháp gián tiếp, ví dụ:IN , EXISTS hoặc INTERSECT .
    • Các cú pháp này được phân tích cú pháp thành một cây chứa áp dụng (phép nối tương quan).
    • Trình tối ưu hóa cố gắng chuyển đơn đăng ký thành một kết hợp thông thường (không phải lúc nào cũng có thể thực hiện được).
    • Băm, hợp nhất và kết hợp bán vòng lặp lồng nhau thông thường không đặt mục tiêu hàng.
    • Áp dụng kết hợp bán luôn đặt mục tiêu hàng.
    • Áp dụng kết nối bán phần có thể được nhận dạng bằng cách có Tham chiếu bên ngoài trên toán tử tham gia vòng lặp lồng nhau.
    • Áp dụng phép nối bán phần không sử dụng toán tử Top (1) ở phía bên trong.
  3. Phần 3 - Chống tham gia
    • Cũng được phân tích cú pháp thành một đơn đăng ký, với nỗ lực viết lại nó dưới dạng một phép nối (không phải lúc nào cũng có thể thực hiện được).
    • Băm, hợp nhất và các vòng lặp lồng nhau thông thường chống tham gia không đặt mục tiêu hàng.
    • Áp dụng kết hợp chống không phải lúc nào cũng đặt mục tiêu hàng.
    • Chỉ các quy tắc tối ưu hóa dựa trên chi phí (CBO) mới chuyển đổi kết hợp chống để áp dụng đặt mục tiêu hàng.
    • Tham gia chống phải nhập CBO làm tham gia (không áp dụng). Nếu không, quá trình kết hợp để áp dụng chuyển đổi không thể xảy ra.
    • Để tham gia CBO, việc ghi lại trước CBO từ đăng ký tham gia phải thành công.
    • CBO chỉ khám phá việc viết lại một liên kết chống để áp dụng trong các trường hợp có triển vọng.
    • Có thể xem các đơn giản hóa trước CBO bằng cờ theo dõi không có giấy tờ 8621.
  4. Phần 4 - Mô hình Chống Tham gia Chống Tham gia
    • Trình tối ưu hóa chỉ đặt mục tiêu hàng để áp dụng liên kết chống khi có lý do đầy hứa hẹn để làm như vậy.
    • Thật không may, nhiều phép biến đổi trình tối ưu hóa tương tác thêm toán tử Top (1) vào bên trong của phép nối chống áp dụng.
    • Toán tử Top là thừa; nó không được yêu cầu về tính đúng đắn hoặc hiệu quả.
    • Trên cùng luôn đặt mục tiêu hàng (không giống như áp dụng, cần có lý do chính đáng).
    • Mục tiêu hàng không chính đáng có thể dẫn đến hiệu suất cực kỳ kém.
    • Chú ý đến một cây con có khả năng đắt tiền trong phần Trên cùng (1) nhân tạo.

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Hiệu suất và bình thường hóa chế độ hàng loạt

  2. Mô hình dữ liệu của cơ quan dư luận

  3. Lỗi T-SQL, cạm bẫy và các phương pháp hay nhất - thuyết xác định

  4. Thời gian cắt tỉa tính từ ngày giờ - theo dõi

  5. SQL AS:Cách sử dụng, ví dụ và cách nó có thể mang lại lợi ích tốt nhất cho bạn