Nested Loop Join
Đây là thuật toán rất đơn giản và cũng rất hiệu quả đối với tập dữ liệu nhỏ, nó lấy mỗi bản ghi trong một bảng (gọi là inner table) và so sánh với từng bản ghi của bảng kia (gọi là outer table) để tìm ra bản ghi thỏa mãn. Thuật toán này có thể được viết ở dạng pseodo-code như sau:
for each row R1 in the outer table
for each row R2 in the inner table
if R1.join_column = R2.join_column
return (R1, R2)
(pseodo-code được copy từ Craig Freedman’s Blog)
ví dụ 1:
Kỹ thuật này đòi hỏi hai bảng phải cùng được sắp xếp theo thứ tự của trường JOIN. Nó đọc từng cặp bản ghi của mỗi bảng và so sánh với nhau. Nếu khớp thì gửi ra tập kết quả. Nếu không thì nó loại bản ghi có trường JOIN nhỏ hơn, đọc tới bản ghi tiếp theo của bảng tương ứng và tiếp tục quá trình. Với thuật toán này, hai bảng được đọc từ đầu và cùng tiến lên song song với nhau. Pseodo-code của thuật toán Merge Join như sau:
get first row R1 from table 1
get first row R2 from table 2
while not at the end of either table
begin
if R1.join_column = R2.join_column
begin
return (R1, R2)
get next row R2 from table 2
end
else if R1.join_column < R2.join_column
get next row R1 from table 1
else
get next row R2 from table 2
end
(pseodo-code được copy từ Craig Freedman’s Blog )
Ví dụ 2: Cùng câu truy vấn như ở phần trước, nhưng bỏ qua mệnh đề WHERE
Với câu lệnh trên thì Merge Join trở nên thích hợp, vì số bản ghi trả về là lớn và cả hai bảng đều đã được sắp xếp (nói chính xác ra là, đối với bảng SalesOrderDetail nó chỉ cần đọc index trên trường ProductID, và tất nhiên index đã sắp xếp sẵn).
Thuật toán này phát huy hiệu quả nhất đối với lượng dữ liệu lớn và không được sắp xếp sẵn. Nó được thực hiện làm hai giai đoạn: xây dựng (build) và dò tìm (probe).
for each row R1 in the build table
begin
calculate hash value on R1.join_column
insert R1 into the appropriate hash bucket
end
for each row R2 in the probe table
begin
calculate hash value on R2.join_column
for each row R1 in the corresponding hash bucket
if R1.join_column = R2.join_column
return (R1, R2)
end
(pseodo-code được copy từ Craig Freedman’s Blog )
Ví dụ 3: giống như ví dụ 2 nhưng thêm một trường OrderQty vào phần SELECT
Ở ví dụ này Hash Join đã được sử dụng, mặc dù số bản ghi được trả về giống như ở ví dụ 2. Lưu ý ở ví dụ 2, bảng SalesOrderDetail chỉ cần đọc index trên trường ProductID là đủ, và vì input cho việc join đã được sắp xêp nên Merge Join đã được dùng. Nhưng ở ví dụ 3, vì có thêm trường OrderQty nên chỉ đọc index trên trường ProductID là không đủ mà hệ thống phải đọc cả vào bảng nữa. Input cho thao tác join lúc này không còn được sắp xếp nữa và do đó, Hash Join trở nên thích hợp hơn.
Trên đây giới thiệu các thuật toán SQL Server dùng để thực thi câu lệnh JOIN. Trên thực tế các thuật toán phức tạp hơn và còn có nhiều biến thể để bộ Optimizer tinh chỉnh trong từng tình huống cụ thể. Tuy nhiên mức sâu nhất mà bạn có thể nhìn vào hệ thống là biết thuật toán nào đã được sử dụng cho câu lệnh, do Microsoft che dấu toàn bộ các chi tiết bên dưới. Việc hiểu biết cơ chế hoạt động của các thuật toán giúp bạn có thêm một công cụ để tối ưu hóa câu lệnh. Ví dụ, với câu truy vấn ở phần Hash Join, khi quan sát kế hoạch thực thi và thấy Hash Join được sử dụng bạn hiểu rằng đây có thể là chỉ dấu câu lệnh chưa được thực hiện tối ưu. Bạn cố gắng tạo thay đổi để hệ thống chuyển sang chọn Merge Join (vì số bản ghi trả về lớn nên Nested Loop Join chắc chắn không thích hợp). Để dùng Merge Join thì đầu vào phải được sắp xếp. Vì thế bạn có thể sửa lại index trên trường ProductID để nó cover cả trường OrderQty. Và giờ câu lệnh đã được thực hiện bằng Merge Join và hiệu năng đã được cải thiện đáng kể:
--Tạo một bảng copy của Sales.SalesOrderDetail
SELECT *
INTO Sales.SalesOrderDetail_2
FROM Sales.SalesOrderDetail
GO
-- tạo các index trên bảng copy
CREATE CLUSTERED INDEX IX_SalesOrderDetail_SalesOrderID_SalesOrderDetailID_2
ON Sales.SalesOrderDetail_2 (
SalesOrderID,
SalesOrderDetailID)
GO
CREATE NONCLUSTERED INDEX IX_SalesOrderDetail_ProductID_2
ON Sales.SalesOrderDetail_2(ProductID)
INCLUDE(OrderQty)
-- so sánh hai câu lệnh:
-- Query 1: câu lệnh trên bảng cũ
SELECT a.SalesOrderDetailID, a.OrderQty, b.Name
FROM Sales.SalesOrderDetail a
JOIN Production.Product b
ON a.ProductID = b.ProductID
-- Query 2: câu lệnh trên bảng copy
SELECT a.SalesOrderDetailID, a.OrderQty, b.Name
FROM Sales.SalesOrderDetail_2 a
JOIN Production.Product b
ON a.ProductID = b.ProductID
0 nhận xét:
Post a Comment
Click to see the code!
To insert emoticon you must added at least one space before the code.