Chỉ số hiệu suất trên ON so với WHERE


26

Tôi có hai bàn

@T1 TABLE
(
    Id INT,
    Date DATETIME
)

@T2 TABLE
(
    Id INT,
    Date DATETIME
)

Các bảng này có một chỉ mục không được nhóm trên (Id, Ngày)

Và tôi tham gia các bảng này

SELECT *
FROM T1 AS t1
INNER JOIN T2 AS t2
ON 
    t1.Id = t2.Id
WHERE 
    t1.Date <= GETDATE()
    AND
    t2.Date <= GETDATE()

Điều này cũng có thể được viết là

SELECT *
FROM T1 AS t1
INNER JOIN T2 AS t2
ON 
    t1.Id = t2.Id
    AND
    t1.Date <= GETDATE()
    AND
    t2.Date <= GETDATE()

Câu hỏi của tôi là, cái nào trong hai truy vấn này cho hiệu năng tốt hơn và tại sao? Hay là họ bằng nhau?


1
Bạn có thực sự có một @table dao động với một chỉ mục không được nhóm bao gồm tất cả các trường và không có chỉ mục được phân cụm không? hay chỉ là một sự đơn giản hóa?
Remus Rusanu

1
Đó là một sự đơn giản hóa cực độ
Erik Bergstedt

Câu trả lời:


32

Hiệu suất sẽ giống nhau. Trình tối ưu hóa sẽ nhận ra điều này và tạo ra cùng một kế hoạch.

Mặt khác tôi sẽ không nói họ bằng nhau. Các hình thức đầu tiên trong câu hỏi là dễ đọc hơn và thường được mong đợi.

Đối với một ví dụ sử dụng một số bảng tôi có trong tay, bạn có thể thấy kế hoạch thực hiện hoàn toàn giống nhau cho dù tôi viết truy vấn như thế nào.

Bạn sẽ có thể xác định các gói truy vấn cho các bảng và tập dữ liệu của riêng bạn để bạn có thể thấy những gì xảy ra trong tình huống của bạn.

SELECT * FROM salestable , custtable 
WHERE salestable.custaccount = custtable.accountnum 
AND salestable.dataareaid = custtable.dataareaid

SELECT * FROM salestable 
JOIN  custtable 
ON salestable.custaccount = custtable.accountnum 
AND salestable.dataareaid = custtable.dataareaid

SELECT * FROM salestable JOIN custtable 
ON salestable.custaccount = custtable.accountnum 
WHERE salestable.dataareaid = custtable.dataareaid

Cung cấp cho các kế hoạch thực hiện

nhập mô tả hình ảnh ở đây


Tôi đồng ý, hình thức đầu tiên dễ đọc hơn và do đó tôi cảm thấy nhẹ nhõm vì chúng bằng nhau. Tôi sẽ chỉ sử dụng hình thức này trong tương lai.
Erik Bergstedt

@ErikBergstedt Tôi đã chỉnh sửa câu trả lời của mình, bạn sẽ có thể xác minh điều này cho tập dữ liệu và cấu trúc bảng của riêng bạn khá dễ dàng khi bạn xem các kế hoạch thực hiện
Tom V - Team Monica

Vâng, tôi đã làm. Cảm ơn bạn. Tôi chỉ tìm kiếm ý kiến ​​thứ 2 vì tôi không tìm thấy câu trả lời.
Erik Bergstedt

Lưu ý: Chúng CHỈ bằng nhau nếu nó là INNER JOIN. Nếu bạn ném OUTER JOINvào thì chúng quyết định không giống nhau.
Kenneth Fisher

22

Chúng giống hệt nhau về mặt ngữ nghĩa và trình tối ưu hóa sẽ không gặp khó khăn khi nhận ra thực tế này và tạo ra các kế hoạch giống hệt nhau.

Tôi có xu hướng đặt các điều kiện tham chiếu cả hai bảng trong ONvà các điều kiện tham chiếu chỉ một bảng trong WHERE.

Đối với việc OUTER JOINSdi chuyển các điều kiện có thể ảnh hưởng đến ngữ nghĩa tuy nhiên.


7

Trong trường hợp đơn giản, nó sẽ giống nhau. Tuy nhiên, tôi đã thấy các truy vấn rất phức tạp với một số phép nối có các kế hoạch khác nhau đáng kể. Một cái gần đây tôi đang làm việc bắt đầu với một bảng có gần 6 triệu hàng được nối với khoảng 20 bảng khác nhau. Chỉ có lần tham gia đầu tiên vào bảng này là tham gia bên trong , tất cả những người khác được tham gia bên ngoài. Bộ lọc trong mệnh đề where được tham số hóa như thế này:

WHERE table1.begindate >= @startdate AND table1.enddate < @enddate 

Bộ lọc này đã được sử dụng sau này trong kế hoạch thay vì trước đó. Khi tôi chuyển các điều kiện này sang phép nối bên trong đầu tiên, kế hoạch đã thay đổi đáng kể khi bộ lọc được áp dụng sớm trong kế hoạch để giới hạn tập kết quả và CPU và thời gian trôi qua của tôi giảm khoảng 310%. Vì vậy, như với nhiều câu hỏi SQL Server, nó phụ thuộc.


2
Bạn có thể thêm chi tiết - có lẽ là ảnh chụp màn hình của sơ đồ kế hoạch thực hiện - vì câu trả lời của bạn dường như mâu thuẫn với tất cả những cái khác?
Kenny Evitt

2
Có kế hoạch cho thấy một thời gian chờ tối ưu hóa?
Martin Smith

Làm thế nào tải CPU có thể giảm hơn 100%?
Michael Green

2

Nói chung, nơi bạn đặt các bộ lọc tạo sự khác biệt.
Mặc dù Tom V nói rằng Trình tối ưu hóa sẽ nhận ra rằng các truy vấn là giống nhau và đưa ra cùng một kế hoạch, nhưng điều đó không phải lúc nào cũng đúng. Nó phụ thuộc vào phiên bản SQL bạn đang sử dụng, mức độ truy vấn của bạn phức tạp và mức độ quan trọng đối với lô tổng thể mà Trình tối ưu hóa xác định truy vấn.

Trình tối ưu hóa có thể quyết định phần này của lô không đáng dành đủ thời gian để cho phép nó đưa ra kế hoạch tốt nhất. Nói chung, bạn sẽ có hiệu suất tốt hơn nếu bạn đặt các điều kiện làm giảm lượng dữ liệu mà truy vấn sẽ cần thực hiện trong mệnh đề ON thay vì mệnh đề WHERE (nếu có thể, vì thực hiện điều này với phép nối ngoài sẽ dẫn đến sản phẩm của Cartesian .)

Việc Nhà phát triển SQL thỉnh thoảng phát hiện các bộ lọc trong mệnh đề WHERE dễ dàng hơn một chút, nhưng tôi đã làm việc trên một số bảng lớn trong đó có các bộ lọc trong mệnh đề ON làm giảm thời gian chạy.

Vì vậy, nếu mệnh đề có khả năng giảm đáng kể số lượng hàng mà truy vấn sẽ đọc, tôi sẽ luôn đặt nó trong mệnh đề BẬT để giúp Trình tối ưu hóa chọn phương án tốt hơn.


1

Trong các trường hợp thông thường, các điều kiện lọc có thể được chỉ định trong các mệnh đề WHERE hoặc THAM GIA. Tôi có xu hướng đặt các bộ lọc trong WHERE trừ khi ưu tiên OUTER THAM GIA có thể bị ảnh hưởng (xem bên dưới) hoặc nếu bộ lọc rất cụ thể cho bảng đó (ví dụ TYPE = 12 để chỉ định một tập hợp con cụ thể của các hàng trong bảng).

Mặt khác, cả hai mệnh đề ON và WHERE đều có thể được sử dụng để chỉ định các điều kiện nối (trái ngược với các điều kiện lọc). Miễn là bạn chỉ sử dụng INNER tham gia, việc bạn sử dụng trong các trường hợp thông thường vẫn không thành vấn đề.

Tuy nhiên, nếu bạn đang sử dụng tham gia OUTER, nó có thể tạo ra sự khác biệt lớn. Ví dụ: nếu bạn chỉ định OUTER THAM GIA giữa hai bảng (t1 và t2) nhưng sau đó, trong mệnh đề WHERE, hãy tiếp tục chỉ định mối quan hệ eqijoin giữa các bảng (ví dụ: t1.col = t2.col), bạn vừa đã chuyển đổi tham gia OUTER thành tham gia INNER! Điều này là do WHERE có thể được sử dụng để chỉ định một Equijoin (hoặc thậm chí có thể tham gia OUTER, tùy thuộc vào phiên bản, sử dụng cú pháp * = không dùng nữa) mà không sử dụng mệnh đề ON và khi WHERE chỉ ra một đẳng thức bên trong giữa các bảng, nó sẽ ghi đè OUTER THAM GIA (nếu có).

Câu hỏi ban đầu là về các bộ lọc, trong đó loại tham gia thường không phải là vấn đề, nhưng tham gia cũng có thể hoạt động như một bộ lọc và trong những tình huống đó, vị trí của điều kiện tham gia chắc chắn có thể quan trọng.


-1

Với INNER THAM GIA, đó là một vấn đề phong cách.

Tuy nhiên, nó trở nên thú vị hơn nhiều với OUTER THAM GIA. Bạn nên khám phá sự khác biệt giữa các truy vấn với OUTER THAM GIA và các điều kiện trong cả mệnh đề ON và mệnh đề WHERE. Tập kết quả không phải lúc nào cũng giống nhau. Là, ví dụ,

OUTER JOIN dbo.x ON a.ID = x.ID ... WHERE x.SomeField IS NOT NULL

giống như

INNER JOIN dbo.x ON a.ID = x.ID AND x.SomeField IS NOT NULL

8
Nếu kết quả là khác nhau (đó là tất nhiên), điểm so sánh hiệu suất là gì?
ypercubeᵀᴹ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.