Sử dụng từ khóa THAM GIA hay không


45

Các truy vấn SQL sau giống nhau:

SELECT column1, column2
FROM table1, table2
WHERE table1.id = table2.id;

SELECT column1, column2
FROM table1 JOIN table2 
ON table1.id = table2.id;

Và chắc chắn dẫn đến các kế hoạch truy vấn giống nhau trên mọi DBMS tôi từng thử.

Nhưng thường xuyên, tôi đọc hoặc nghe một ý kiến ​​rằng cái này chắc chắn tốt hơn cái kia. Đương nhiên, những tuyên bố này không bao giờ được chứng minh bằng một lời giải thích.

Nơi tôi làm việc, phiên bản thứ hai dường như được ưa chuộng bởi phần lớn các nhà phát triển khác, và vì vậy tôi cũng có xu hướng hướng tới phong cách đó để giảm thiểu bất ngờ. Nhưng trong thâm tâm, tôi thực sự đang nghĩ đến điều đầu tiên (vì đó là cách ban đầu tôi học nó).

Là một trong những hình thức khách quan tốt hơn so với hình thức khác? Nếu không, lý do để sử dụng cái này hơn cái kia là gì?


1
Tại sao không hồ sơ nó và cho phần còn lại của chúng tôi biết kết quả? Nói chung, hiệu suất vượt trội hơn nhiều so với sở thích phong cách.
Demian Brecht

3
"dẫn đến các kế hoạch truy vấn giống nhau trên mọi DBMS mà tôi từng thử" Nếu điều này có thể có câu trả lời về hiệu suất, thì nó đã hỏi nó trên stackoverflow.com. Than ôi, họ là cùng một truy vấn.
Độc thân Tăng tốc

À .. Bỏ lỡ điều đó :)
Demian Brecht

2
"Chủ quan" không có nghĩa là "ý kiến ​​của bạn". Tôi đã chỉnh sửa này để loại đáp ứng các tiêu chí đặt ra trong các câu hỏi thường gặp .
Aaronaught

Tôi cũng có xu hướng hướng tới phong cách đó để giảm thiểu bất ngờ Tôi nghĩ bạn vừa trả lời câu hỏi của riêng bạn. Bất ngờ là xấu.
Pieter B

Câu trả lời:


60

Tôi thấy rằng hình thức thứ hai là tốt hơn. Đó có thể là vì đó là cách tôi học nó, tôi sẽ thừa nhận, nhưng tôi có một lý do cụ thể - tách rời các mối quan tâm. Đặt các trường bạn đang sử dụng để tham gia các bảng trong mệnh đề where có thể dẫn đến khó khăn trong việc hiểu các truy vấn.

Ví dụ: lấy truy vấn sau:

select *
from table1, table2, table3, table4
where table1.id = table2.id
and table2.id = table3.id
and table3.id = table4.id
and table1.column1 = 'Value 1'

Truy vấn trên có các điều kiện nối bảng và điều kiện logic nghiệp vụ thực tế, tất cả được kết hợp thành một không gian duy nhất. Với một truy vấn lớn, điều này có thể rất khó hiểu.

Tuy nhiên, bây giờ hãy lấy mã này:

select *
from table1 join table2 on table1.id = table2.id
join table3 on table2.id = table3.id
join table4 on table3.id = table4.id
where table1.column1 = 'Value 1'

Trong trường hợp này, mọi thứ phải làm với các bảng hoặc cách chúng liên quan đều được tách biệt với mệnh đề from, trong khi logic nghiệp vụ thực tế cho hạn chế truy vấn nằm trong mệnh đề where. Tôi nghĩ rằng điều đó dễ hiểu hơn nhiều, đặc biệt đối với các truy vấn lớn hơn.


Đây là cách hợp lý duy nhất để làm điều đó đặc biệt là khi bạn vượt qua hai bảng hoặc cần kết hợp các liên kết trái, phải và đầy đủ.
aglassman

5
+1 Để "phân tách mối quan tâm" kết hợp dữ liệu lại với nhau, trong đó các mệnh đề chỉ ra các tập hợp con của dữ liệu mà bạn quan tâm.

39

Cú pháp nối thay thế cú pháp dấu phẩy cũ vào năm 1992. Hiện tại không có lý do gì để viết mã bằng cú pháp dấu phẩy. Bạn không đạt được gì và bạn phải chịu một số vấn đề mà bạn không gặp phải với cú pháp rõ ràng.

Ở nơi đầu tiên khi bạn nhận được các truy vấn phức tạp hơn, rất dễ thực hiện một phép nối chéo ngẫu nhiên bằng cách bỏ lỡ một điều kiện where. Đây là điều mà cú pháp nối rõ ràng có thể ngăn chặn xảy ra vì bạn sẽ gặp lỗi cú pháp.

Nếu bạn có ý định tham gia chéo, cú pháp nối rõ ràng sẽ làm rõ điều đó trong khi trong cú pháp ngầm, ai đó đang bảo trì có thể cho rằng bạn quên thêm mệnh đề where.

Sau đó, có vấn đề liên kết trái và phải có vấn đề trong ít nhất một số dbs sử dụng cú pháp ngầm. Chúng không được dùng trong SQL Server và trên thực tế không trả về kết quả chính xác ngay cả trong các phiên bản cũ hơn. Không có truy vấn nào cần tham gia bên ngoài nên chứa cú pháp ngầm định trong SQL Server.

Hơn nữa, tôi đã thấy các câu hỏi ở đây và trên các trang web khác, nơi kết quả sai đã xảy ra khi mọi người trộn các kết nối ngầm và rõ ràng (khi thêm một liên kết trái chẳng hạn), vì vậy, đó là một ý tưởng tồi để trộn chúng.

Cuối cùng, nhiều người sử dụng các phép nối ngầm không thực sự hiểu các phép nối. Đây là một sự hiểu biết quan trọng mà bạn phải có để truy vấn cơ sở dữ liệu một cách hiệu quả.


Cám ơn vì đã giải thích. Khi tôi được dạy, chúng tôi đã được hiển thị cả hai cú pháp, nhưng sự khác biệt không được giải thích. Đôi khi tôi đã xoay sở để tạo ra các truy vấn bị thiếu trong đó thẳng thắn sẽ tăng số lượng văn bản chỉ bằng cách tham gia rõ ràng ở vị trí đầu tiên.
awiebe

8

Hà. Tôi chỉ tình cờ tìm thấy một câu trả lời có thể cho câu hỏi của riêng tôi, trong khi xem tài liệu cho PostgreQuery . Để tóm tắt những gì trang này giải thích, truy vấn kết quả vẫn giống nhau, nhưng số lượng kế hoạch mà trình tối ưu hóa phải xem xét tăng theo cấp số nhân với số lượng tham gia.

Sau khoảng sáu lần tham gia như vậy, con số rất lớn đến nỗi thời gian lập kế hoạch truy vấn có thể đáng chú ý và sau khoảng mười, trình tối ưu hóa sẽ chuyển từ tìm kiếm toàn diện các kế hoạch sang tìm kiếm xác suất và có thể không đến kế hoạch tối ưu .

Bằng cách đặt tham số thời gian chạy, bạn có thể hướng dẫn người lập kế hoạch xử lý các phép nối bên trong và chéo được đề cập rõ ràng khác với các phép nối ngầm, buộc chúng lên đầu kế hoạch và không khám phá các tùy chọn khác.

Lưu ý, hành vi mặc định là giống nhau trong cả hai trường hợp và để có được các kế hoạch thay thế đòi hỏi kiến ​​thức về các phần bên trong của dbms và đặc thù của các bảng được đề cập để có kết quả khác


2
Bạn đã hơi hiểu lầm những tài liệu đó, tuy nhiên. Thứ nhất, thực sự có ba ngưỡng. Một người bắn GEQO như bạn đã chỉ ra; hai cái còn lại (từ và tham gia giới hạn sụp đổ) cuối cùng làm cho máy bào dính vào việc chọn các chỉ mục áp dụng thay vì tổ chức lại thứ tự tham gia. Thứ hai và cũng quan trọng, các truy vấn được viết lại khi chúng được phân tích cú pháp. Điều này dẫn đến các truy vấn ví dụ đầu tiên được phân tích cú pháp vào cùng một cây truy vấn chính xác như của truy vấn thứ hai - các ngưỡng sau đó cho PG biết liệu có nên thử đặt hàng lại các phép nối hay không.
Denis de Bernardy

8

Vâng, đây là quan điểm lý thuyết tập hợp của nó:

Khi bạn sử dụng dấu phẩy để phân tách hai (hoặc nhiều) tên bảng, thứ bạn dự định là sản phẩm cartesian. Mỗi hàng của bảng 'bên trái' sẽ được 'khớp' (nối) với bảng bên phải.

Bây giờ nếu bạn viết một cái gì đó trong mệnh đề where, thì giống như đặt một điều kiện vào 'phép nối' này cho biết hàng nào sẽ 'nối' với hàng nào.

Đây thực sự là "tham gia" các hàng :) và do đó từ khóa tham gia giúp cung cấp cú pháp dễ đọc hơn và dễ hiểu hơn khi bạn thực sự muốn tham gia vào một số giá trị chung. Tương tự như những gì @Dustin đã làm rõ ở trên.

Bây giờ, mọi DBMS đều thông minh, tức là nó không tính toán sản phẩm cartesian trước rồi lọc dữ liệu (cực kỳ lãng phí) mà thay vào đó dựa trên cấu trúc truy vấn. Điều duy nhất tôi có thể nghĩ đến là, khi bạn yêu cầu nó 'tham gia', nó giống như làm cho hoạt động tham gia trở nên rõ ràng và có thể giúp chạy mã nhanh hơn (bao nhiêu? Bạn sẽ phải lập hồ sơ và xem) nhưng trong Trường hợp được phân tách bằng dấu phẩy, cần một chút thời gian để tìm ra chiến lược tối ưu. Tôi có thể sai, nhưng tôi chỉ đưa ra một phỏng đoán có giáo dục về cách người ta sẽ mã hóa nó ...


5

Tôi nghĩ nói chung là tốt hơn để sử dụng các câu lệnh THAM GIA cho trường hợp đó.

Nếu trong tương lai, một tình huống phát sinh đòi hỏi phải thay đổi câu lệnh từ INNER THAM GIA sang NGOÀI RA, thì điều này sẽ dễ thực hiện hơn với câu lệnh thứ hai.


3

Bất kỳ RDBMS nào cũng sẽ làm cho chúng giống nhau về mặt thực thi. Nó liên quan đến việc một người dễ đọc và biểu cảm hơn.

Sử dụng THAM GIA để rõ ràng kết hợp tham gia là gì và lựa chọn thực tế là gì, như trong:

select name, deptname
from people p, departments d
where p.deptid = d.id and p.is_temp = 'Y'

so với

select name, deptname
from people p
    inner join departments d on p.deptid = d.id
where p.is_temp = 'Y'

Trường hợp thứ hai làm cho nó ngay lập tức rõ ràng đó là điều kiện tham gia, và đó là tiêu chí lựa chọn.


1

Tôi chỉ có một lần nhìn thấy hai kết quả trong một tập hợp tối ưu hóa khác nhau và nếu bộ nhớ phục vụ thì đó là trong ms-sql2k trên một truy vấn thực sự nhiều lông. Trong đó một ví dụ, hình thức cũ được sử dụng với * = dẫn đến hiệu suất nhanh hơn khoảng 4 lần. Không ai, kể cả những người làm công nghệ Microsoft của chúng tôi có thể giải thích lý do tại sao. Các MS đã gán cho nó một sai lầm. Tôi chưa bao giờ nhìn thấy nó một lần nữa.

Vì hầu hết RDBMS đủ thông minh để không thực hiện các cartesian đầy đủ, lý do lớn nhất tôi có thể nghĩ đến là không sử dụng nó (bên cạnh đó là khấu hao) là hầu hết những người dưới 30 - 35 tuổi mà tôi đã làm việc chưa bao giờ thấy hình thức cũ trước đây và bị mất một cách khủng khiếp khi họ gặp nó.


Tất nhiên, cú pháp nối trái không bao giờ cung cấp kết quả chính xác một cách đáng tin cậy (xem BOL cho SQL Server 2000) vì vậy ngay cả khi nó nhanh hơn, tôi sẽ thay thế nó.
HLGEM

Tôi chưa bao giờ gặp phải điều đó, và tìm kiếm bằng dấu hoa thị không bao giờ kết thúc tốt, bạn có một ví dụ không?
Bill

-1

Kiểu cũ đã bị phản đối, bạn không nên sử dụng nó.

Thậm chí không nên tranh cãi về việc cái nào tốt hơn hay không. Mã mới không nên sử dụng cú pháp cũ.


Tôi nghĩ rằng câu trả lời này không thực sự thêm bất cứ điều gì mà không nói lý do tại sao nó không được sử dụng và không nên sử dụng.
RemcoGerlich

1
@RemcoGerlich tại sao nó không được thảo luận ở đây. Điều đang thảo luận ở đây là liệu nên sử dụng cú pháp cũ hay mới. Cho dù cái này tốt hơn cái kia hay không là moot: bạn không nên sử dụng cú pháp cũ. Câu hỏi tại sao là một cuộc thảo luận khác. (một trong đó đã được giải quyết 20 năm trước.)
Pieter B

-4

Một lý do cho cú pháp ngắn gọn hơn là nó ngắn gọn hơn, vì vậy nếu bạn cảm thấy thoải mái với nó thì nó dễ đọc hơn. Tôi nghĩ về trường hợp dài dòng tương tự như viết ra số học trong COBOL, ví dụ NHIỀU A BỞI B GIVING C.


Downvoters: Có bất cứ điều gì thực sự không chính xác trong phản hồi này, hoặc họ chỉ "không đồng ý với bạn" downvote?
Adam Libuša
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.