2010-01-21 28 views
5

Tôi thường thấy mình muốn viết một truy vấn SQL như sau:SQL: Là một truy vấn như thế này OK hoặc là có một cách hiệu quả hơn để làm điều đó, như sử dụng một tham gia?

SELECT body 
    FROM node_revisions 
where vid = (SELECT vid 
       FROM node 
       WHERE nid = 4); 

Tôi biết rằng có tham gia và các công cụ bạn có thể làm, nhưng họ dường như làm cho mọi việc phức tạp hơn. Được tham gia một cách tốt hơn để làm điều đó? Nó có hiệu quả hơn không? Dễ hiểu?

+1

Tôi sẵn sàng đặt cược rằng, trên SQL Server, truy vấn đó và tham gia tương đương hợp lý sẽ có các kế hoạch thực thi truy vấn giống hệt nhau. – Dana

Trả lời

7

Tham gia có hiệu quả hơn vì cơ sở dữ liệu được viết với các hoạt động đặt trong tâm trí (và tham gia được đặt hoạt động).

Tuy nhiên, hiệu suất sẽ thay đổi từ cơ sở dữ liệu sang cơ sở dữ liệu, cách các bảng được cấu trúc, lượng dữ liệu trong chúng và truy vấn sẽ trả về bao nhiêu.

Nếu lượng dữ liệu nhỏ, tôi sẽ sử dụng truy vấn phụ như của bạn thay vì tham gia.

Đây là những gì một tham gia sẽ như thế nào:

SELECT body 
FROM node_revisions nr 
INNER JOIN node n 
    ON nr.vid = n.vid 
WHERE n.nid = 4 

tôi sẽ không sử dụng các truy vấn mà bạn đăng, là có cơ hội nhiều hơn một kỷ lục nút với một nid = 4, mà có thể gây ra lỗi đối với nó.

Tôi sẽ sử dụng:

SELECT body 
FROM node_revisions 
WHERE vid IN (SELECT vid 
      FROM node 
      WHERE nid = 4); 

Đây có phải là có thể đọc được nhiều hơn hoặc dễ hiểu? Trong trường hợp này, đó là vấn đề sở thích cá nhân.

+0

Đó là cách nhiều hơn sở thích cá nhân. Tôi muốn nhìn thấy một tham gia trên hai cột bằng cách sử dụng IN mà so sánh trong khả năng đọc. Thành thật mà nói, lạm dụng IN, với tôi, có thể là một triệu chứng của một vấn đề khái niệm cốt lõi trong SQL. – ErikE

1
select 
    body 
from node_revisions A 
where exists (select 'x' 
       from Node B 
       Where A.Vid = B.Vid and B.NID=4) 
+2

Tại sao điều đó tốt hơn? Nó có vẻ phức tạp hơn. –

+0

Nó phức tạp hơn nhưng nó cũng không làm điều tương tự. Đây là một phép nối bán, mà trong một số trường hợp cho phép máy chủ cơ sở dữ liệu thực hiện một số tối ưu hóa. Nó cũng sẽ luôn luôn chỉ trả về một hàng từ bảng chính cho dù có bao nhiêu hàng phù hợp được tìm thấy trong bảng truy vấn phụ. Lưu ý rằng bạn không thể tham chiếu trong truy vấn chính tới các cột trong truy vấn phụ, nhưng đó là điểm: bạn đang kiểm tra * tồn tại *, không kéo dữ liệu.Ngoài ra, nếu bảng truy vấn phụ có MANY hàng trên mỗi hàng trong bảng bên ngoài, cú pháp tồn tại có thể hiệu quả hơn nhiều vì nó có thể dừng lại sau khi tìm chỉ một. – ErikE

+0

Điều này không tương đương về mặt logic với truy vấn ban đầu. Trong trường hợp truy vấn con trả lại nhiều hàng, điều này sẽ hoạt động và truy vấn ban đầu sẽ không thành công. Điều này sẽ tương đương với một truy vấn với 'IN' thay vì' = '. Tuy nhiên, tất cả các công cụ hiện đại có thể tối ưu hóa cả hai 'EXISTS' và' IN' thành một nửa tham gia. – Quassnoi

3

Câu trả lời cho bất kỳ câu hỏi hiệu suất liên quan trong cơ sở dữ liệu là nó phụ thuộc và chúng tôi rất ngắn về chi tiết trong OP. Biết không có chi tiết cụ thể về tình hình của bạn ... (do đó, đây là những quy tắc chung của ngón tay cái)

tham gia được tốt hơn và dễ dàng hơn để hiểu

  • Nếu vì một số lý do bạn cần nhiều phím cột (tanh) , bạn có thể tiếp tục sử dụng tham gia và chỉ cần tack vào một biểu thức khác để điều kiện tham gia.
  • Nếu trong tương lai bạn thực sự cần phải tham gia dữ liệu phụ trợ, khung tham gia đã có sẵn.
  • Điều này làm rõ hơn chính xác những gì bạn đang tham gia và nơi các chỉ mục sẽ được triển khai.
  • Sử dụng kết nối giúp bạn tham gia tốt hơn và suy nghĩ tốt hơn về việc tham gia.
  • tham gia rất rõ ràng về những gì bảng đang chơi trong

truy vấn bằng văn bản không có gì để làm với effiency *

Các truy vấn bạn viết và những gì thực sự được chạy có ít để làm với nhau. Có nhiều cách để viết một truy vấn nhưng chỉ có rất ít cách để lấy dữ liệu, và tùy thuộc vào công cụ truy vấn để quyết định. Điều này liên quan chủ yếu đến các chỉ mục. Nó rất có thể để viết bốn truy vấn trông hoàn toàn khác nhau nhưng nội bộ làm điều tương tự.

(* Có thể viết một truy vấn khủng khiếp đó là không hiệu quả nhưng phải mất một loại đặc biệt của điên để làm điều đó.)

select 
    body 

from node_revisions nr 

join node n 
on n.vid = nr.vid 

where n.nid = 4 
1

Mới nhất mã MySQL 6.x sẽ tự động chuyển đổi mà TRÊN biểu hiện thành một INNER JOIN sử dụng một bán tham gia subquery tối ưu hóa, làm cho 2 báo cáo phần lớn tương đương:

http://forge.mysql.com/worklog/task.php?id=3740

nhưng, trên thực tế viết nó ra là khá đơn giản để làm, vì INNER JOIN là kiểu nối mặc định, và làm điều này sẽ không phụ thuộc vào máy chủ tối ưu hóa nó đi (mà nó có thể quyết định không vì một lý do nào đó và điều đó không cần thiết phải di động). tất cả mọi thứ đều bình đẳng, tại sao không đi với:

select body from node_revisions r, node n where r.vid = n.vid and n.node = 4 
3

Tôi nghĩ rằng việc tham gia dễ hiểu hơn và có thể hiệu quả hơn. Trường hợp của bạn là khá đơn giản, vì vậy nó có lẽ là một toss-up. Đây là cách tôi sẽ viết nó:

SELECT body 
    FROM node_revisions 
    inner join node 
     on (node_revisions.vid = node.vid) 
    WHERE node.nid = 4 
1

Tôi không thấy điều gì sai với những gì bạn viết và một trình tối ưu hóa tốt thậm chí có thể thay đổi nó để tham gia nếu nó phù hợp.

1
SELECT body 
FROM node_revisions 
WHERE vid = 
     (
     SELECT vid 
     FROM node 
     WHERE nid = 4 
     ) 

Truy vấn này là hợp lý tương đương với một tham gia nếu và chỉ nếu nid là một PRIMARY KEY hoặc được bao phủ bởi một hạn chế UNIQUE.

Nếu không, các truy vấn không tương đương: tham gia sẽ luôn thành công, trong khi truy vấn con sẽ thất bại nếu có nhiều hơn 1 hàng trong node với nid = 4.

Nếu nidPRIMARY KEY thì JOIN và truy vấn phụ sẽ có cùng hiệu suất.

Trong trường hợp của một tham gia, node sẽ được thực hiện hàng đầu

Trong trường hợp của một subquery, subquery sẽ được thực hiện một lần và chuyển đổi thành một const trên phân tích sân khấu.

+0

Yup, nid và vid là các khóa chính duy nhất. –

+0

'@Brian T. Hannan': thì các truy vấn giống nhau. 'JOIN' và truy vấn con sẽ thực hiện tương tự. – Quassnoi

2

Một tham gia là thú vị:

select body 
from node_revisions nr 
join node n on nr.vid = n.vid 
where n.vid = 4 

Nhưng bạn cũng có thể thể hiện một tham gia mà không có một tham gia [!]:

select body 
from node_revisions nr, node n 
where n.nid = 4 and nr.vid = n.vid 

Điều thú vị đủ, SQL Server đưa ra một kế hoạch truy vấn nhẹ khác nhau trên cả hai truy vấn, trong khi tham gia có quét chỉ mục nhóm, "tham gia không tham gia" có chỉ mục nhóm được tìm kiếm ở vị trí của nó, cho biết đó là số better, ít nhất trong trường hợp này!

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