2008-10-23 44 views
21

Tôi có truy vấn sau đây:Thứ tự MySQL được đánh giá theo thứ tự nào?

SELECT c.* 
FROM companies AS c 
JOIN users AS u USING(companyid) 
JOIN jobs AS j USING(userid) 
JOIN useraccounts AS us USING(userid) 
WHERE j.jobid = 123; 

Tôi có câu hỏi sau:

  1. là cú pháp SỬ DỤNG đồng nghĩa với cú pháp ON?
  2. Các kết nối này được đánh giá từ trái sang phải phải không? Nói cách khác, truy vấn này có nói: x = công ty JOIN người dùng; y = x JOIN công việc; z = y THAM GIA tài khoản người dùng;
  3. Nếu câu trả lời cho câu hỏi 2 là có, có an toàn để giả định rằng bảng công ty có cột companyid, userid và jobid không?
  4. Tôi không hiểu làm thế nào các mệnh đề WHERE có thể được sử dụng để chọn hàng trên bảng công ty khi nó được đề cập đến bí danh "j"

Bất kỳ trợ giúp sẽ được đánh giá cao!

Trả lời

23
  1. SỬ DỤNG (tên trường) là cách viết tắt của bảng ON1.fieldname = table2.fieldname.

  2. SQL không xác định 'thứ tự' trong đó JOINS được thực hiện vì nó không phải là bản chất của ngôn ngữ. Rõ ràng là một lệnh phải được xác định trong câu lệnh, nhưng một INNER JOIN có thể được coi là giao hoán: bạn có thể liệt kê chúng theo thứ tự bất kỳ và bạn sẽ nhận được kết quả tương tự. Điều đó nói rằng, khi xây dựng một SELECT ... JOIN, đặc biệt là một trong đó bao gồm LEFT JOINs, tôi đã tìm thấy nó có ý nghĩa để coi JOIN thứ ba là tham gia bảng mới với kết quả của JOIN đầu tiên, thứ tư. THAM GIA tham gia các kết quả của JOIN thứ hai, v.v.

    Rất hiếm khi, thứ tự được chỉ định có thể ảnh hưởng đến hành vi của trình tối ưu hóa truy vấn, do cách nó ảnh hưởng đến chẩn đoán.

  3. Không. Cách truy vấn được lắp ráp, yêu cầu các công ty và người dùng đều có companyid, công việc có userid và jobid và useraccounts có userid. Tuy nhiên, chỉ một trong số các công ty hoặc người dùng cần một userid để JOIN hoạt động.

  4. Mệnh đề WHERE đang lọc toàn bộ kết quả - tức là tất cả các cột được gắn kết - sử dụng cột do bảng công việc cung cấp.

+0

"SQL không xác định thứ tự 'trong đó JOINS được thực hiện" là sai. Xem https://dev.mysql.com/doc/refman/5.5/en/nested-join-optimization.html trong "Các ví dụ trước minh họa các điểm sau:" –

+0

Tôi nghĩ rằng liên kết đó không rõ ràng về việc chứng minh quan điểm của bạn. Tuy nhiên, tôi đã viết câu trả lời gần 10 năm trước nên tôi không nhớ tại sao tôi lại nói vậy. Nhưng tôi có thể đưa ra giả thuyết rằng đó là điều tôi đã hiểu chuẩn SQL. – staticsan

0

SEE http://dev.mysql.com/doc/refman/5.0/en/join.html

VÀ bắt đầu đọc ở đây:


Tham gia chế biến thay đổi trong MySQL 5.0.12

Bắt đầu với MySQL 5.0.12, tự nhiên tham gia và tham gia với SỬ DỤNG, bao gồm các biến thể nối ngoài, được xử lý theo tiêu chuẩn SQL: 2003. Mục đích là để căn chỉnh cú pháp và ngữ nghĩa của MySQL đối với NATURAL JOIN và JOIN ... SỬ DỤNG theo SQL: 2003. Tuy nhiên, những thay đổi này trong xử lý kết nối có thể dẫn đến các cột đầu ra khác nhau cho một số kết nối. Ngoài ra, một số truy vấn dường như hoạt động chính xác trong các phiên bản cũ hơn phải được viết lại để tuân thủ tiêu chuẩn.

Những thay đổi này có năm khía cạnh chính:

  • Cách mà MySQL xác định các cột kết quả của TỰ NHIÊN hoặc SỬ DỤNG tham gia hoạt động (và do đó kết quả của toàn bộ mệnh đề FROM).

  • Mở rộng SELECT * và SELECT tbl_name. * Vào danh sách các cột đã chọn.

  • Độ phân giải của tên cột trong tham gia NATURAL hoặc USING.

  • Chuyển đổi NATURAL hoặc USING tham gia JOIN ... ON.

  • Độ phân giải của tên cột trong điều kiện BẬT của JOIN ... BẬT.

9

Tôi không thể trả lời một chút về cú pháp SỬ DỤNG. Lạ nhỉ. Tôi chưa bao giờ thấy nó trước đây, thay vào đó luôn sử dụng mệnh đề ON.

Nhưng những gì tôi thể cho bạn biết là thứ tự của THAM GIA hoạt động được xác định động bởi truy vấn tối ưu khi nó xây dựng kế hoạch truy vấn của mình, dựa trên một hệ thống chẩn đoán tối ưu hóa, một số trong đó là:

  1. JOIN có được thực hiện trên một trường khóa chính không? Nếu vậy, điều này sẽ được ưu tiên cao trong kế hoạch truy vấn.

  2. JOIN có được thực hiện trên trường khóa ngoài không? Điều này cũng được ưu tiên cao.

  3. Chỉ mục tồn tại trên trường đã tham gia? Nếu vậy, hãy nhấn mức độ ưu tiên.

  4. Hoạt động JOIN có được thực hiện trên một trường trong mệnh đề WHERE không? Biểu thức mệnh đề WHERE có thể được đánh giá bằng cách kiểm tra chỉ mục (thay vì thực hiện quét bảng) không? Đây là cơ hội tối ưu hóa chính, do đó, nó sẽ nhận được mức độ ưu tiên chính.

  5. Cardinality của cột được kết nối là gì? Các cột có số lượng cardinality cao cho phép trình tối ưu hóa nhiều cơ hội phân biệt đối xử với các kết quả sai (các đối tượng không thỏa mãn mệnh đề WHERE hoặc mệnh đề ON), vì vậy các tham gia có số lượng cao thường được xử lý trước khi kết nối với cardinality thấp.

  6. Có bao nhiêu hàng thực tế trong bảng đã tham gia? Tham gia vào một bảng chỉ với 100 giá trị sẽ tạo ra ít sự bùng nổ dữ liệu hơn là tham gia vào một bảng với mười triệu hàng.

Nhưng dù sao ... có rất nhiều biến tham gia vào kế hoạch thực hiện truy vấn. Nếu bạn muốn xem cách MySQL tối ưu hóa các truy vấn của nó, hãy sử dụng cú pháp GIẢI THÍCH.

Và đây là một bài viết tốt để đọc:

http://www.informit.com/articles/article.aspx?p=377652


ON EDIT:

Để trả lời câu hỏi thứ 4 của bạn: Bạn chưa truy vấn "công ty" bảng. Bạn đang truy vấn sản phẩm chéo đã tham gia của TẤT CẢ bốn bảng trong mệnh đề FROM và USING của bạn.

Bí danh "j.jobid" chỉ là tên đủ điều kiện của một trong các cột trong bộ sưu tập bảng đã tham gia đó.

+0

Có thực sự là một chéo sản phẩm? Tôi nghĩ SELECT * FROM table_a JOIN table_b USING (common_column) sẽ mang lại tất cả các hàng từ table_a có khớp với bất kỳ hàng nào trong trường common_column của table_b? Điều này có thể ít hơn n hàng. Không phải một sản phẩm chéo sẽ trả về n x m nhiều hàng? –

+0

Xin lỗi. Tôi không biết gì về cú pháp SỬ DỤNG, vì vậy tôi không thể bình luận về cách nó hoạt động. Nhận xét "sản phẩm chéo" chỉ là tham chiếu đến các tham gia nói chung, có khả năng tạo ra một vụ nổ tổ hợp các bộ dữ liệu, đó là lý do tại sao số lượng thẻ được trình tối ưu hóa đưa vào tài khoản. – benjismith

+0

INDEX = Luôn luôn tốt? –

0

Im không chắc chắn về ON vs SỬ DỤNG phần (mặc dù website này nói rằng họ đều giống nhau)

Đối với các câu hỏi đặt hàng, hoàn toàn của nó thực hiện (và có lẽ query) cụ thể. MYSQL rất có thể chọn một đơn đặt hàng khi biên dịch yêu cầu. Nếu bạn muốn thực thi một thứ tự cụ thể bạn sẽ phải 'làm tổ' truy vấn của bạn:

SELECT c.* 
FROM companies AS c 
    JOIN (SELECT * FROM users AS u 
     JOIN (SELECT * FROM jobs AS j USING(userid) 
       JOIN useraccounts AS us USING(userid) 
       WHERE j.jobid = 123) 
    ) 

như đối với phần 4: đâu là giới hạn khoản gì các hàng từ bảng công việc có đủ điều kiện để được gia nhập vào. Vì vậy, nếu có hàng sẽ tham gia do các userids phù hợp nhưng không có jobid đúng thì chúng sẽ bị bỏ qua.

0

1) Sử dụng là không chính xác giống như trên, nhưng nó là tay ngắn mà cả hai bảng có một cột có cùng tên bạn đang tham gia vào ... xem: http://www.java2s.com/Tutorial/MySQL/0100__Table-Join/ThekeywordUSINGcanbeusedasareplacementfortheONkeywordduringthetableJoins.htm

Đó là khó khăn hơn để đọc theo ý kiến ​​của tôi, vì vậy tôi sẽ đánh vần các tham gia.

3) Không rõ ràng từ truy vấn này, nhưng tôi đoán là không.

2) Giả sử bạn đang tham gia thông qua các bảng khác (không phải tất cả trực tiếp trên companyies) thứ tự trong truy vấn này không thành vấn đề ... thấy sự so sánh dưới đây:

Origional:

SELECT c.* 
    FROM companies AS c 
    JOIN users AS u USING(companyid) 
    JOIN jobs AS j USING(userid) 
    JOIN useraccounts AS us USING(userid) 
WHERE j.jobid = 123 

Những gì tôi nghĩ rằng đó là khả năng gợi ý:

SELECT c.* 
    FROM companies AS c 
    JOIN users AS u on u.companyid = c.companyid 
    JOIN jobs AS j on j.userid = u.userid 
    JOIN useraccounts AS us on us.userid = u.userid 
WHERE j.jobid = 123 

Bạn đồng uld chuyển đổi các dòng của bạn tham gia công việc & usersaccounts tại đây.

gì nó sẽ trông như thế nào nếu tất cả mọi thứ đã gia nhập vào công ty:

SELECT c.* 
    FROM companies AS c 
    JOIN users AS u on u.companyid = c.companyid 
    JOIN jobs AS j on j.userid = c.userid 
    JOIN useraccounts AS us on us.userid = c.userid 
WHERE j.jobid = 123 

này không thực sự có ý nghĩa logic ... trừ khi mỗi người dùng có công ty riêng của họ.

4.) Sự kỳ diệu của sql là bạn chỉ có thể hiển thị các cột nhất định, nhưng tất cả chúng đều của họ để phân loại và lọc ...

nếu bạn trở

SELECT c.*, j.jobid.... 

bạn có thể thấy rõ những gì nó đã được lọc trên, nhưng máy chủ cơ sở dữ liệu không quan tâm nếu bạn xuất một hàng hay không để lọc.

0

Đây là một câu trả lời chi tiết hơn về JOIN được ưu tiên. Trong trường hợp của bạn, các JOIN s đều là giao hoán. Hãy thử một nơi mà họ không.

schema tích xây dựng:

CREATE TABLE users (
    name text 
); 

CREATE TABLE orders (
    order_id text, 
    user_name text 
); 

CREATE TABLE shipments (
    order_id text, 
    fulfiller text 
); 

Thêm dữ liệu:

INSERT INTO users VALUES ('Bob'), ('Mary'); 

INSERT INTO orders VALUES ('order1', 'Bob'); 

INSERT INTO shipments VALUES ('order1', 'Fulfilling Mary'); 

Chạy truy vấn:

SELECT * 
    FROM users 
     LEFT OUTER JOIN orders 
     ON orders.user_name = users.name 
     JOIN shipments 
     ON shipments.order_id = orders.order_id 

Kết quả:

Chỉ có hàng Bob đang trở

Phân tích:

Trong truy vấn này LEFT OUTER JOIN được đánh giá đầu tiên và JOIN được đánh giá trên kết quả tổng hợp của LEFT OUTER JOIN.

Thứ hai truy vấn:

SELECT * 
    FROM users 
     LEFT OUTER JOIN (
     orders 
     JOIN shipments 
     ON shipments.order_id = orders.order_id) 
     ON orders.user_name = users.name 

Kết quả:

Một hàng cho Bob (với các dữ liệu thực hiện) và một hàng cho Mary với NULLs cho dữ liệu thực hiện.

Phân tích:

Các ngoặc thay đổi trình tự đánh giá.


Hơn nữa tài liệu MySQL là https://dev.mysql.com/doc/refman/5.5/en/nested-join-optimization.html

Các vấn đề liên quan