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

SỬ DỤNG HINT và DISABLE_OPTIMIZED_NESTED_LOOP

Một trong những thuật toán có sẵn để nối hai bảng lại với nhau trong SQL Server là Vòng lặp lồng nhau. Phép nối vòng lặp lồng nhau sử dụng một đầu vào nối làm bảng đầu vào bên ngoài và một đầu vào làm bảng đầu vào bên trong. Vòng lặp bên ngoài lặp lại từng hàng của bảng đầu vào bên ngoài. Vòng lặp bên trong, được thực thi cho mỗi hàng bên ngoài, tìm kiếm các hàng phù hợp trong bảng nhập liệu bên trong.

Đây được gọi là phép nối các vòng lặp lồng nhau.

Nếu bạn có chỉ mục về điều kiện nối trong bảng đầu vào bên trong, thì không cần thiết phải thực hiện vòng lặp bên trong cho mỗi hàng của bảng bên ngoài. Thay vào đó, bạn có thể chuyển giá trị từ bảng bên ngoài làm đối số tìm kiếm và kết nối tất cả các hàng được trả về của bảng bên trong với các hàng từ bảng bên ngoài.

Việc tìm kiếm theo bảng bên trong là một truy cập ngẫu nhiên. SQL Server, bắt đầu từ phiên bản 2005, có tối ưu hóa sắp xếp hàng loạt (đừng nhầm lẫn với toán tử Sắp xếp trong Chế độ hàng loạt cho các chỉ mục Columnstore). Mục đích của việc tối ưu hóa là để sắp xếp các khóa tìm kiếm từ bảng bên ngoài trước khi lấy dữ liệu từ bảng bên trong. Do đó, một truy cập ngẫu nhiên sẽ là tuần tự.

Kế hoạch thực thi không hiển thị hoạt động sắp xếp hàng loạt như một toán tử riêng biệt. Thay vào đó, bạn có thể thấy thuộc tính Optimized =true trong toán tử Vòng lặp lồng nhau. Nếu có thể xem sắp xếp hàng loạt như một toán tử riêng biệt trong kế hoạch, nó sẽ giống như sau:

Trong kế hoạch giả này, chúng tôi đọc dữ liệu từ chỉ mục ix_CustomerID không phân cụm theo thứ tự của khóa chỉ mục CustomerID này. Sau đó, chúng ta cần thực hiện Tra cứu Khóa trong chỉ mục được phân nhóm, vì ix_CustomerID không phải là một chỉ mục bao trùm. Key Lookup là một hoạt động tìm kiếm khóa chỉ mục theo cụm - một truy cập ngẫu nhiên. Để làm cho nó tuần tự, SQL Server có thể thực hiện sắp xếp hàng loạt bằng khóa chỉ mục nhóm.

Để tìm hiểu thêm về sắp xếp hàng loạt, vui lòng tham khảo bài viết Sắp xếp hàng loạt và các vòng lặp lồng nhau của tôi.

Tối ưu hóa này cung cấp một sự thúc đẩy lớn với số lượng hàng đủ. Bạn có thể đọc thêm về kết quả thử nghiệm của nó trong blog TỐI ƯU HÓA Tham gia vòng lặp lồng nhau, được tạo bởi Craig Freedman, một nhà phát triển trình tối ưu hóa.

Tuy nhiên, nếu số hàng thực tế ít hơn dự kiến, thì chi phí bổ sung cho CPU để xây dựng loại này có thể che giấu lợi ích của nó, tăng mức tiêu thụ CPU và giảm hiệu suất của nó.

Hãy xem xét ví dụ cụ thể này:

use tempdb;
go
-- create a test table (SalesOrderID - clustered PK)
create table dbo.SalesOrder(SalesOrderID int identity primary key, CustomerID int not null, SomeData char(200) not null);
go
-- add test data
with n as (select top(1000000) rn = row_number() over(order by (select null)) from sys.all_columns c1,sys.all_columns c2)
insert dbo.SalesOrder(CustomerID, SomeData) select rn%500000, str(rn,100) from n;
-- create a clustered index
create index ix_c on dbo.Salesorder(CustomerID);
go
-- the batch sort optimization is enabled by default (Nested Loops: Optimized = true)
select * from dbo.SalesOrder with(index(ix_c)) where CustomerID < 1000;
-- disable it with the DISABLE_OPTIMIZED_NESTED_LOOP hint (Nested Loops: Optimized = false)
select * from dbo.SalesOrder with(index(ix_c)) where CustomerID < 1000 option(use hint('DISABLE_OPTIMIZED_NESTED_LOOP'));
go

Kết quả trả về:

Tôi muốn thu hút sự chú ý của bạn đến thứ tự khác nhau của các hàng trong đầu ra. Máy chủ trả về các hàng theo thứ tự xử lý chúng vì chúng tôi chưa chỉ định rõ ràng ORDER BY. Trong trường hợp đầu tiên, chúng tôi đọc dần dần từ chỉ mục ix_c. Tuy nhiên, để tối ưu hóa các lần đọc ngẫu nhiên từ chỉ mục được phân nhóm, chúng tôi lọc các hàng bằng khóa chỉ mục SalesOrderID được phân cụm. Trong trường hợp thứ hai, không có sắp xếp, cũng như việc đọc được thực hiện theo thứ tự khóa CustomerID của chỉ mục không phân biệt ix_c.

Sự khác biệt so với cờ theo dõi 2340

Mặc dù tài liệu chỉ định cờ theo dõi 2340 tương đương với gợi ý DISABLE_OPTIMIZED_NESTED_LOOP, nhưng nó không thực sự đúng.

Hãy xem xét ví dụ sau, nơi tôi sẽ sử dụng lệnh CẬP NHẬT THỐNG KÊ… VỚI PAGECOUNT lệnh không có tài liệu để đánh lừa trình tối ưu hóa bằng cách nói rằng bảng chiếm nhiều trang hơn thực tế. Sau đó, hãy xem các truy vấn sau:

  1. Không có bất kỳ gợi ý nào (Tôi đã thêm MAXDOP để giữ một kế hoạch đơn giản);
  2. Với gợi ý DISABLE_OPTIMIZED_NESTED_LOOP;
  3. Với cờ theo dõi 2340.
-- create a huge table
update statistics dbo.SalesOrder with pagecount = 100000;
go
set showplan_xml on;
go
-- 1. without hints
select * from dbo.SalesOrder with(index(ix_c)) where CustomerID < 1000000 option(maxdop 1);
-- 2. hint
select * from dbo.SalesOrder with(index(ix_c)) where CustomerID < 1000000 option(use hint('DISABLE_OPTIMIZED_NESTED_LOOP'), maxdop 1);
-- 3. trace flag
select * from dbo.SalesOrder with(index(ix_c)) where CustomerID < 1000000 option(querytraceon 2340, maxdop 1);
go
set showplan_xml off;
go

Kết quả là chúng tôi có các kế hoạch sau:

Các vòng lặp lồng nhau có thuộc tính Optimized =false trong cả ba kế hoạch. Thực tế là bằng cách tăng chiều rộng bảng, chúng tôi cũng tăng chi phí truy cập dữ liệu. Khi chi phí đủ cao, SQL Server có thể sử dụng toán tử Sắp xếp rõ ràng, thay vì toán tử sắp xếp hàng loạt ngầm định. Chúng ta có thể thấy điều này trong kế hoạch truy vấn đầu tiên.

Trong truy vấn thứ hai, chúng tôi đã sử dụng gợi ý DISABLE_OPTIMIZED_NESTED_LOOP để tắt sắp xếp hàng loạt ngầm định. Tuy nhiên, nó loại bỏ sự sắp xếp rõ ràng bởi một toán tử riêng biệt.

Trong kế hoạch thứ ba, chúng ta có thể thấy rằng mặc dù thêm cờ theo dõi 2340, toán tử sắp xếp vẫn tồn tại.

Do đó, sự khác biệt của gợi ý so với cờ như sau:gợi ý vô hiệu hóa việc tối ưu hóa bằng cách chuyển đổi một truy cập ngẫu nhiên thành một truy cập nối tiếp tùy thuộc vào thực tế là máy chủ triển khai nó với sắp xếp hàng loạt ngầm định hay với toán tử Sắp xếp riêng biệt.

P.S. Các kế hoạch có thể phụ thuộc vào thiết bị. Do đó, nếu bạn không chạy được các truy vấn này, hãy cố gắng tăng hoặc giảm kích thước cột SomeData char (200) trong mô tả bảng dbo.SalesOrder.

Bài viết do nhóm Codingsight dịch với sự cho phép của tác giả.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Xây dựng Mô hình Dữ liệu cho Hệ thống Quản lý Bãi đỗ xe

  2. Sự khác biệt giữa khóa chính và khóa duy nhất

  3. Cơ sở dữ liệu RAC khởi động không thành công với lỗi ORA-12547

  4. Thủ tục được lưu trữ để xóa bản ghi trùng lặp trong bảng SQL

  5. Cung cấp quà Giáng sinh:Mô hình dữ liệu của ông già Noel