Sự khác biệt giữa CTE và SubQuery?


143

Từ bài đăng này Làm thế nào để sử dụng ROW_NUMBER trong quy trình sau đây?

Có hai phiên bản câu trả lời trong đó một câu sử dụng a sub-queryvà phiên bản kia sử dụng a CTEđể giải quyết cùng một vấn đề.

Bây giờ, lợi thế của việc sử dụng một CTE (Common Table Expression)' truy vấn phụ' là gì (do đó, dễ đọc hơn những gì truy vấn đang thực sự làm)

Ưu điểm duy nhất của việc sử dụng CTEhơn sub-selectlà tôi thực sự có thể đặt tên cho sub-query. Có sự khác biệt nào khác giữa hai điều đó khi CTE được sử dụng như một CTE đơn giản (không đệ quy) không?


Câu hỏi phái sinh với thảo luận tốt: stackoverflow.com/q/11169550/781695
người dùng

7
IMO, bất cứ ai nghĩ rằng CTE đều khó đọc hơn , một loạt các truy vấn đan xen khổng lồ đã không thấy đống rác của các truy vấn hình răng cưa khó hiểu được sử dụng trên phần lớn các hệ thống quản lý dữ liệu doanh nghiệp. , Truy vấn không tầm thường lớn thường đột ngột dễ dàng hơn để đọc sau hoặc bởi đôi mắt mới hơn subqueries, và ít nhất là trong trường hợp của Postgres kỳ diệu thực hiện nhiều hơn trong nhiều trường hợp. ([Vì những lý do tôi vẫn chưa hiểu [( stackoverflow.com/questions/33731068/ triệt ), vì điều ngược lại có vẻ nhiều khả năng hơn.)
zxq9

Câu trả lời:


102

Trong các phiên bản CTE truy vấn phụ và đơn giản (không đệ quy), chúng có thể rất giống nhau. Bạn sẽ phải sử dụng trình lược tả hồ sơ và thực thi thực tế để phát hiện bất kỳ sự khác biệt nào và điều đó sẽ cụ thể cho thiết lập của bạn (vì vậy chúng tôi không thể cho bạn biết câu trả lời đầy đủ).

Nói chung ; Một CTE có thể được sử dụng đệ quy; một truy vấn phụ không thể. Điều này làm cho chúng đặc biệt phù hợp với cấu trúc cây.


1
Xin lỗi, tôi nên đã rõ ràng hơn trong câu hỏi của tôi. Điều gì sẽ là sự khác biệt giữa CTE và Subquery trong bối cảnh CTE được sử dụng truy vấn THÍCH THÍCH?
dance2die

2
@Marc Gravell: Chúng tôi có thể làm nhiều hơn thế, vì hành vi của trình hồ sơ không được đảm bảo, so với hành vi của CTE, đó là (về mặt đánh giá).
casperOne

1
Không chắc chắn bao nhiêu tuyên bố này có ý nghĩa cho những người nhìn vào CTS và sự khác biệt truy vấn phụ - A CTE can be used recursively; a sub-query cannot. Một ví dụ sẽ là tuyệt vời.
Aniket Thakur

88

Ưu điểm chính của Biểu thức bảng chung (khi không sử dụng nó cho các truy vấn đệ quy ) là đóng gói, thay vì phải khai báo truy vấn phụ ở mọi nơi bạn muốn sử dụng, bạn có thể xác định nó một lần, nhưng có nhiều tham chiếu với nó

Tuy nhiên, điều này không có nghĩa là nó chỉ được thực hiện một lần (theo các lần lặp trước của chính câu trả lời này , cảm ơn tất cả những người đã bình luận). Truy vấn chắc chắn có tiềm năng được thực hiện nhiều lần nếu được tham chiếu nhiều lần; trình tối ưu hóa truy vấn cuối cùng đưa ra quyết định về cách giải thích CTE.


"Hãy nghĩ về CTE như một biến bảng tạm thời" có nghĩa là CTE được lưu trữ trong đĩa hoặc trong bộ nhớ?
dance2die

Theo định nghĩa, bạn không thể sử dụng CTE hoặc truy vấn con trong nhiều truy vấn. Tôi khá chắc chắn rằng trình tối ưu hóa xử lý truy vấn con giống như cách nó sẽ xử lý CTE (chỉ đánh giá kết quả được đặt một lần, bất kể số lần sử dụng trong truy vấn 1 lần)
AlexCuse

@AlexCuse: Tôi nghĩ rằng tôi đã làm rõ bối cảnh của CTE, nhưng tôi đã thêm nhiều hơn để thử và làm rõ hơn.
casperOne

@AlexCuse: Cũng không có hàm ý rằng CTE hoặc truy vấn con có thể được sử dụng ở nhiều nơi. Sự khác biệt giữa CTE và trình tối ưu hóa là hành vi của CTE được đảm bảo, trong khi hành vi của trình tối ưu hóa thì không.
casperOne

và tôi sẽ thừa nhận rằng có thể có một số trường hợp cạnh mà trình tối ưu hóa cuộn cảm và truy vấn con được đánh giá nhiều lần, mặc dù vậy tôi không gặp phải trường hợp nào. Sau đó, một lần nữa, tôi sử dụng CTE bất cứ nơi nào tôi có thể;)
AlexCuse

15

CTELà hữu ích nhất cho đệ quy:

WITH hier(cnt) AS (
        SELECT  1
        UNION ALL
        SELECT  cnt + 1
        FROM    hier
        WHERE   cnt < @n
        )
SELECT  cnt
FROM    hier

sẽ trả về @nhàng (tối đa 101). Hữu ích cho lịch, hàng giả, vv

Họ cũng dễ đọc hơn (theo ý kiến ​​của tôi).

Ngoài ra, CTEsubqueriesgiống hệt nhau.


Trong MSSQL, bạn cần thêm dấu chấm phẩy (;) trước VỚI, hãy đặt hàng một cách khôn ngoan, bạn sẽ gặp lỗi. nó phải được;WITH blabla AS ...)
Obinna Nnenanya

2
@ObinnaNnenanya: chỉ khi đó không phải là tuyên bố đầu tiên trong đợt. Chấm dứt lệnh của bạn với dấu chấm phẩy là một ý tưởng tốt dù sao, mặc dù SQL Server không thực thi nó trong các phiên bản hiện hành khác so với trước đây WITH, MERGEvà tương tự
Quassnoi

10

Một điểm khác biệt chưa được đề cập là một CTE duy nhất có thể được tham chiếu trong một số phần của liên minh


8

Trừ khi tôi thiếu một cái gì đó, bạn có thể đặt tên cho CTE và các truy vấn con một cách dễ dàng.

Tôi đoán sự khác biệt chính là khả năng đọc (tôi thấy CTE dễ đọc hơn vì nó xác định truy vấn con của bạn lên phía trước hơn là ở giữa).

Và nếu bạn cần làm bất cứ điều gì với đệ quy, bạn sẽ gặp một chút rắc rối khi làm điều đó với một truy vấn phụ;)


1
Tôi không chắc có bất kỳ sự khác biệt phi thẩm mỹ nào (mặc dù tôi hy vọng rằng trong một số tình huống nhất định có thể có một chút khác biệt trong kế hoạch thực hiện). Quan tâm để soi sáng cho tôi?
AlexCuse

2
Bạn có thể đặt tên cho CTE, nhưng bạn chỉ có thể đặt bí danh cho các truy vấn con. Sự khác biệt là, bạn có thể sử dụng lại các CTE với nhiều bí danh (xem ví dụ của @Michael Petito trong nhận xét của mình cho casperOne). Tôi không biết cách nào để làm điều đó với các truy vấn con.
kmote

7

Một thực tế quan trọng mà không ai đề cập đến là (ít nhất là trong postgres), CTE là hàng rào tối ưu hóa:

https://blog.2ndquadrant.com/postgresql-ctes-are-optimization-fences/

Đó là, chúng sẽ được coi là truy vấn nguyên tử của riêng chúng, thay vì được xếp vào toàn bộ kế hoạch truy vấn. Tôi thiếu chuyên môn để đưa ra một lời giải thích tốt hơn, nhưng bạn nên kiểm tra ngữ nghĩa cho phiên bản sql bạn đang sử dụng; đối với người dùng nâng cao, việc có thể tạo một hàng rào tối ưu hóa có thể giúp thực hiện nếu bạn ở cấp độ chuyên gia trong việc kiểm soát kế hoạch truy vấn; tuy nhiên, trong 99% trường hợp, bạn nên tránh cố gắng nói cho người lập kế hoạch truy vấn phải làm gì, bởi vì những gì bạn nghĩ sẽ nhanh hơn có khả năng tồi tệ hơn những gì nó nghĩ sẽ nhanh hơn. :-)


6

Thêm vào câu trả lời của người khác, nếu bạn có một và cùng một truy vấn con được sử dụng nhiều lần, bạn có thể thay thế tất cả các truy vấn con này bằng một CTE. Điều này cho phép bạn sử dụng lại mã của bạn tốt hơn.


4

Một điều bạn cũng cần hiểu là trong các phiên bản SQL Server cũ hơn (có nhiều người vẫn cần hỗ trợ cơ sở dữ liệu SQL Server 2000), CTE không được phép và sau đó bảng dẫn xuất là giải pháp tốt nhất của bạn.


2

GỢI Ý: (MAXRECURSION n)

bạn có thể giới hạn số mức đệ quy được phép cho một câu lệnh cụ thể bằng cách sử dụng MAXRECURSIONgợi ý và giá trị trong khoảng từ 0 đến 32.767 trong OPTIONmệnh đề

Ví dụ: bạn có thể thử:

OPTION 
      (MAXRECURSION 150)

GO
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.