SQL rõ ràng và tham gia SQL tham gia


399

Có sự khác biệt hiệu quả trong một kết nối bên trong rõ ràng và ngầm? Ví dụ:

SELECT * FROM
table a INNER JOIN table b
ON a.id = b.id;

so với

SELECT a.*, b.*
FROM table a, table b
WHERE a.id = b.id;

11
Câu hỏi hay. Tôi tò mò tại sao tham gia rõ ràng được sử dụng ở tất cả. Có phải là không thể thực hiện tất cả các truy vấn mà không có nó?
andrew

6
sử dụng từ khóa EXPLAIN để biết sự khác biệt về cả hai truy vấn .. sử dụng THAM GIA và xem sự khác biệt .. Nếu bạn thử trong một bảng hơn 100 nghìn bản ghi, bạn có thể thấy sự khác biệt ...
Jeyanth Kumar

@andrew Câu hỏi của tôi thực sự là liệu tham gia ngầm có phải là một dạng "hack" hay không (như trong "Một truy vấn liên quan đến nhiều hơn một bảng, không sử dụng tham gia? Đó có phải là hack không?")
bobobobo

3
Chúng khác nhau, việc tham gia ngầm sẽ khiến bạn ngạc nhiên mỗi lần khi xử lý các giá trị null; sử dụng kết nối rõ ràng và tránh các lỗi phát sinh khi "không có gì thay đổi!"
BlackTigerX

1
Không có sự khác biệt. ,CROSS JOINvới ràng buộc lỏng lẻo hơn và INNER JOINCROSS JOINvới ràng buộc ONnhư WHEREnhưng chặt chẽ hơn. Điều quan trọng để thực hiện là làm thế nào DBMS tối ưu hóa các truy vấn.
philipxy

Câu trả lời:


132

Hiệu suất khôn ngoan, chúng hoàn toàn giống nhau (ít nhất là trong SQL Server).

PS: Xin lưu ý rằng IMPLICIT OUTER JOINcú pháp không được dùng kể từ SQL Server 2005. ( IMPLICIT INNER JOINCú pháp như được sử dụng trong câu hỏi vẫn được hỗ trợ)

Sự phản đối của "Kiểu cũ" THAM GIA Cú pháp: Chỉ một phần


4
@lomaxx, chỉ vì lợi ích rõ ràng, bạn có thể chỉ định cú pháp của 2 trong câu hỏi là bị phản đối?
J Wynia

8
Bạn có thể cung cấp tài liệu hỗ trợ? Điều này nghe có vẻ sai trên nhiều cấp độ.
NotMe

21
Làm thế nào để bạn phản đối tiêu chuẩn SQL?
David Crawshaw

7
@david Crenshaw, tham gia ngầm không còn trong tiêu chuẩn và đã được 18 năm.
HLGEM

11
Cái gọi là "tham gia ngầm" của giống 'bên trong' hoặc 'chéo' vẫn còn trong Tiêu chuẩn. SQL Server là ti các "kiểu cũ" bên ngoài tham gia cú pháp (ví dụ *==*) mà chưa bao giờ được tiêu chuẩn.
onedaywhen

129

Cá nhân tôi thích cú pháp nối vì nó làm rõ hơn rằng các bảng được nối và cách chúng được nối. Hãy thử so sánh các truy vấn SQL lớn hơn nơi bạn chọn từ 8 bảng khác nhau và bạn có rất nhiều bộ lọc ở đâu. Bằng cách sử dụng cú pháp nối, bạn tách ra các phần trong đó các bảng được nối, đến phần bạn đang lọc các hàng.


4
Tôi hoàn toàn đồng ý, nhưng đây là loại ngoài chủ đề. OP hỏi về hiệu quả.
biệt thự

56

Trên MySQL 5.1.51, cả hai truy vấn đều có kế hoạch thực hiện giống hệt nhau:

mysql> explain select * from table1 a inner join table2 b on a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.02 sec)

mysql> explain select * from table1 a, table2 b where a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.00 sec)

table1có 166208 hàng; table2có khoảng 1000 hàng.

Đây là một trường hợp rất đơn giản; điều đó không có nghĩa là chứng minh rằng trình tối ưu hóa truy vấn sẽ không bị lẫn lộn và tạo ra các kế hoạch khác nhau trong trường hợp phức tạp hơn.


Đây phải là câu trả lời được chấp nhận. Điều này là chính xác, kế hoạch là như nhau (hoặc gần với các tuyên bố lớn hơn) nhưng số lượng hồ sơ sẽ quyết liệt, do đó gây ra sự khác biệt trong hiệu suất.
SovietFrontier

37

Cú pháp thứ hai có khả năng không mong muốn của phép nối chéo: bạn có thể thêm các bảng vào phần TỪ mà không cần mệnh đề WHERE tương ứng. Điều này được coi là có hại.


Điều gì xảy ra nếu tên bảng trong mệnh đề from được tạo từ các bảng được sử dụng trong mệnh đề where?
Jus12

bạn cũng có thể tham gia chéo với cú pháp THAM GIA rõ ràng. ( stackoverflow.com/a/44438026/929164 ) bạn có thể có nghĩa là nó ít nghiêm ngặt hơn, do đó dễ bị lỗi người dùng hơn.
Daniel Dubovski

15

Câu trả lời đầu tiên bạn đưa ra sử dụng cú pháp tham gia ANSI, câu trả lời khác là hợp lệ và sẽ hoạt động trong bất kỳ cơ sở dữ liệu quan hệ nào.

Tôi đồng ý với grom rằng bạn nên sử dụng cú pháp tham gia ANSI. Như họ đã nói, lý do chính là cho sự rõ ràng. Thay vì có một mệnh đề where có nhiều biến vị ngữ, một số trong đó tham gia các bảng và một số khác giới hạn các hàng được trả về bằng cú pháp nối ANSI, bạn đang làm cho nó rõ ràng những điều kiện nào đang được sử dụng để tham gia các bảng của bạn và đang được sử dụng để hạn chế các kết quả.


5

Hiệu suất khôn ngoan, chúng hoàn toàn giống nhau (ít nhất là trong SQL Server) nhưng lưu ý rằng chúng không dùng cú pháp nối này và nó không được hỗ trợ bởi sql server2005.

Tôi nghĩ rằng bạn đang nghĩ về các toán tử * = và = * không dùng nữa so với "tham gia ngoài".

Tôi vừa mới thử nghiệm hai định dạng đã cho và chúng hoạt động chính xác trên cơ sở dữ liệu SQL Server 2008. Trong trường hợp của tôi, họ đã mang lại kế hoạch thực hiện giống hệt nhau, nhưng tôi không thể tự tin nói rằng điều này sẽ luôn đúng.


5

@lomaxx: Chỉ cần làm rõ, tôi khá chắc chắn rằng cả hai cú pháp trên đều được SQL Serv 2005 hỗ trợ. Tuy nhiên cú pháp bên dưới KHÔNG được hỗ trợ

select a.*, b.*  
from table a, table b  
where a.id *= b.id;

Cụ thể, nối ngoài (* =) không được hỗ trợ.


2
Thành thật mà nói tôi sẽ không sử dụng nó ngay cả trong SQL Server 2000, cú pháp * = thường đưa ra câu trả lời sai. Đôi khi nó diễn giải những điều này như tham gia chéo.
HLGEM

2

Trên một số cơ sở dữ liệu (đặc biệt là Oracle), thứ tự của các phép nối có thể tạo ra sự khác biệt lớn đối với hiệu năng truy vấn (nếu có nhiều hơn hai bảng). Trên một ứng dụng, chúng tôi có hai đơn hàng chênh lệch cường độ trong một số trường hợp. Sử dụng cú pháp nối bên trong cho phép bạn kiểm soát điều này - nếu bạn sử dụng cú pháp gợi ý đúng.

Bạn đã không chỉ định cơ sở dữ liệu nào bạn đang sử dụng, nhưng xác suất đề xuất SQL Server hoặc MySQL, nơi nó không có sự khác biệt thực sự.


1
Leigh, bạn có thể sử dụng các gợi ý trong tham gia ngầm quá.
SquareCog

1
Trong Oracle, cực kỳ hiếm khi lệnh tham gia ảnh hưởng đến kế hoạch thực hiện một cách có ý nghĩa. Xem bài viết này của Jonathan Lewis cho một lời giải thích.
Jon Heller

1

Như Leigh Caldwell đã tuyên bố, trình tối ưu hóa truy vấn có thể tạo ra các gói truy vấn khác nhau dựa trên chức năng trông giống như câu lệnh SQL. Để đọc thêm về điều này, hãy xem hai bài đăng trên blog sau: -

Một bài đăng từ Nhóm Trình tối ưu hóa Oracle

Một bài đăng khác từ blog "Dữ liệu có cấu trúc"

Tôi hy vọng bạn tìm thấy điều này thú vị.


Mike, sự khác biệt mà họ đang nói đến là bạn cần chắc chắn rằng nếu bạn chỉ định một phép nối rõ ràng, bạn chỉ định điều kiện nối để tham gia chứ không phải bộ lọc. Bạn sẽ lưu ý rằng đối với các truy vấn đúng ngữ nghĩa, kế hoạch thực hiện là như nhau.
SquareCog

1

Hiệu suất khôn ngoan, nó không nên làm cho bất kỳ sự khác biệt. Cú pháp nối rõ ràng có vẻ sạch hơn đối với tôi vì nó xác định rõ mối quan hệ giữa các bảng trong mệnh đề from và không làm lộn xộn mệnh đề where.


0

Về cơ bản, sự khác biệt giữa hai là một cái được viết theo cách cũ, trong khi cái kia được viết theo cách hiện đại. Cá nhân, tôi thích tập lệnh hiện đại sử dụng các định nghĩa bên trong, bên trái, bên ngoài, bên phải bởi vì chúng dễ giải thích hơn và làm cho mã dễ đọc hơn.

Tuy nhiên, khi xử lý các phép nối bên trong, không có sự khác biệt thực sự về khả năng đọc, nó có thể trở nên phức tạp khi xử lý các phép nối trái và phải như trong phương thức cũ hơn bạn sẽ có được một cái gì đó như thế này:

SELECT * 
FROM table a, table b
WHERE a.id = b.id (+);

Trên đây là cách cũ về cách viết bên trái được viết trái ngược với những điều sau:

SELECT * 
FROM table a 
LEFT JOIN table b ON a.id = b.id;

Như bạn có thể thấy, cách hiện đại của cách viết kịch bản làm cho truy vấn dễ đọc hơn. (Nhân tiện cũng vậy đối với các phép nối phải và phức tạp hơn một chút đối với các phép nối ngoài).

Quay trở lại tấm nồi hơi, nó không tạo ra sự khác biệt cho trình biên dịch SQL về cách truy vấn được viết khi nó xử lý chúng theo cùng một cách. Tôi đã thấy một sự kết hợp của cả hai trong cơ sở dữ liệu của Oracle, nơi có nhiều người viết vào đó, cả người già và người trẻ. Một lần nữa, nó tập trung vào mức độ dễ đọc của kịch bản và nhóm bạn đang phát triển.


-1

Theo kinh nghiệm của tôi, việc sử dụng cú pháp liên kết ngang với mệnh đề thường tạo ra một kế hoạch thực thi bị tổn thương não, đặc biệt nếu bạn đang sử dụng một sản phẩm Microsoft SQL. Chẳng hạn, cách mà SQL Server cố gắng ước tính số lượng hàng của bảng, thật khủng khiếp. Sử dụng cú pháp nối bên trong cung cấp cho bạn một số kiểm soát về cách thực hiện truy vấn. Vì vậy, từ quan điểm thực tế, với bản chất tự nhiên của công nghệ cơ sở dữ liệu hiện tại, bạn phải đi với sự tham gia bên trong.


5
Bạn có bất cứ bằng chứng nào về điều này? Bởi vì câu trả lời được chấp nhận nói khác.
cimmanon
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.