Sự khác biệt giữa CTE và Bảng Temp là gì?


174

Sự khác biệt giữa Biểu thức bảng chung (CTE) và bảng tạm thời là gì? Và khi nào tôi nên sử dụng cái này hơn cái kia?

CTE

WITH cte (Column1, Column2, Column3)
AS
(
    SELECT Column1, Column2, Column3
    FROM SomeTable
)

SELECT * FROM cte

Bảng tạm thời

SELECT Column1, Column2, Column3
INTO #tmpTable
FROM SomeTable

SELECT * FROM #tmpTable


Câu trả lời:


200

Điều này khá rộng, nhưng tôi sẽ cho bạn câu trả lời chung chung nhất có thể.

CTE ...

  • Không thể hiểu được (nhưng có thể sử dụng các chỉ mục hiện có trên các đối tượng được tham chiếu)
  • Không thể có những ràng buộc
  • Cơ bản là dùng một lần VIEWs
  • Chỉ tồn tại cho đến khi truy vấn tiếp theo được chạy
  • Có thể đệ quy
  • Không có số liệu thống kê chuyên dụng (dựa vào số liệu thống kê về các đối tượng cơ bản)

#Temp Bàn ...

  • Các bảng được vật chất hóa thực sự tồn tại trong tempdb
  • Có thể được lập chỉ mục
  • Có thể có những ràng buộc
  • Kiên trì cho cuộc sống của KẾT NỐI hiện tại
  • Có thể được tham chiếu bởi các truy vấn hoặc tài liệu phụ khác
  • Có số liệu thống kê chuyên dụng được tạo ra bởi động cơ

Theo như khi sử dụng mỗi, họ có trường hợp sử dụng rất khác nhau. Nếu bạn sẽ có một tập kết quả rất lớn, hoặc cần tham khảo nó nhiều lần, hãy đặt nó vào một #tempbảng. Nếu nó cần phải được đệ quy, là dùng một lần, hoặc chỉ để đơn giản hóa một cái gì đó một cách logic, thì một CTEưu tiên.

Ngoài ra, không bao giờCTE nên được sử dụng cho hiệu suất . Bạn gần như sẽ không bao giờ tăng tốc mọi thứ bằng cách sử dụng CTE, bởi vì, một lần nữa, nó chỉ là một chế độ xem dùng một lần. Bạn có thể thực hiện một số điều gọn gàng với chúng nhưng tăng tốc truy vấn không thực sự là một trong số chúng.


tăng tốc một MERGE lớn bằng cách sử dụng CTE là một điều
AgentFire

1
Tăng tốc nhiều truy vấn bằng cách sử dụng CTE cũng là một điều vì với CTE, bạn có thể thêm kiến ​​thức kinh doanh của riêng mình để vượt trội hơn trình tối ưu hóa truy vấn. Ví dụ: bạn có thể có phần 1 của CTE chọn từ các bảng mà bạn biết rằng các hàng kết quả sẽ rất nhỏ. Trong cùng một truy vấn, bạn có thể nối kết quả nhỏ này với một số kết quả lớn hơn và bỏ qua hoàn toàn các vấn đề gây ra bởi thống kê cũ, v.v. Để làm điều này, bạn cần thêm gợi ý truy vấn để buộc thứ tự. Nó hoạt động, nó cải thiện hiệu suất.
Dave Hilditch

"Không bao giờ được sử dụng cho hiệu suất" là một tuyên bố rộng rãi và hơi chủ quan, mặc dù tôi hiểu quan điểm của bạn. Mặc dù, ngoài các ý kiến ​​khác, một hiệu suất tiềm năng khác có thể xảy ra khi sử dụng CTE có thể xảy ra khi chuyển sang CTE đệ quy từ một hình thức đệ quy khác như gọi thủ tục đệ quy hoặc con trỏ.
JD

29

BIÊN TẬP:

Xin vui lòng xem ý kiến ​​của Martin dưới đây:

CTE không được vật chất hóa như một bảng trong bộ nhớ. Nó chỉ là một cách để đóng gói một định nghĩa truy vấn. Trong trường hợp của OP, nó sẽ được nội tuyến và giống như chỉ làm SELECT Column1, Column2, Column3 FROM SomeTable. Hầu hết thời gian họ không được vật chất hóa lên phía trước, đó là lý do tại sao điều này không trả về hàng nào WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.X, cũng kiểm tra các kế hoạch thực hiện. Mặc dù đôi khi có thể hack kế hoạch để có được một ống chỉ. Có một mục kết nối yêu cầu một gợi ý cho việc này. - Martin Smith ngày 15 tháng 2 năm 12 lúc 17:08


Câu trả lời gốc

CTE

Đọc thêm về MSDN

CTE tạo bảng đang được sử dụng trong bộ nhớ, nhưng chỉ hợp lệ cho truy vấn cụ thể theo sau nó. Khi sử dụng đệ quy, đây có thể là một cấu trúc hiệu quả.

Bạn cũng có thể muốn xem xét sử dụng một biến bảng. Điều này được sử dụng như một bảng tạm thời được sử dụng và có thể được sử dụng nhiều lần mà không cần phải được vật liệu hóa lại cho mỗi lần tham gia. Ngoài ra, nếu bạn cần duy trì một vài bản ghi ngay bây giờ, hãy thêm một vài bản ghi sau lần chọn tiếp theo, thêm một vài bản ghi sau một op khác, sau đó trả lại chỉ một số bản ghi, đây có thể là một cấu trúc tiện dụng, vì nó không Không cần phải bỏ sau khi thực hiện. Chủ yếu chỉ là cú pháp đường. Tuy nhiên, nếu bạn giữ số lượng hàng thấp, nó sẽ không bao giờ thành hiện thực. Xem sự khác biệt giữa bảng tạm thời và biến bảng trong SQL Server là gì? để biết thêm chi tiết.

Bảng tạm thời

Đọc thêm về MSDN - Cuộn xuống khoảng 40%

Một bảng tạm thời theo nghĩa đen là một bảng được tạo trên đĩa, chỉ trong một cơ sở dữ liệu cụ thể mà mọi người đều biết có thể bị xóa. Trách nhiệm của một nhà phát triển tốt là phá hủy các bảng đó khi không còn cần thiết, nhưng một DBA cũng có thể xóa sạch chúng.

Bảng tạm thời có hai loại: Địa phương và toàn cầu. Về mặt MS Sql Server, bạn sử dụng một #tableNamechỉ định cho cục bộ và ##tableNamechỉ định cho toàn cục (lưu ý việc sử dụng một hoặc hai # làm đặc tính nhận dạng).

Lưu ý rằng với các bảng tạm thời, trái ngược với các biến của bảng hoặc CTE, bạn có thể áp dụng các chỉ mục và tương tự, vì đây là các bảng hợp pháp theo nghĩa thông thường của từ này.


Nói chung, tôi sẽ sử dụng các bảng tạm thời cho các truy vấn dài hơn hoặc lớn hơn và các CTE hoặc biến bảng nếu tôi đã có một bộ dữ liệu nhỏ và muốn nhanh chóng tạo ra một đoạn mã cho một số mã nhỏ. Kinh nghiệm và lời khuyên của người khác chỉ ra rằng bạn nên sử dụng CTE nơi bạn có một số lượng nhỏ hàng được trả về từ đó. Nếu bạn có số lượng lớn, có lẽ bạn sẽ được hưởng lợi từ khả năng lập chỉ mục trên bảng tạm thời.


11
CTE không được vật chất hóa như một bảng trong bộ nhớ. Nó chỉ là một cách để đóng gói một định nghĩa truy vấn. Trong trường hợp của OP, nó sẽ được nội tuyến và giống như chỉ làmSELECT Column1, Column2, Column3 FROM SomeTable
Martin Smith

4
Hầu hết thời gian họ không được vật chất hóa lên phía trước, đó là lý do tại sao điều này không trả về hàng nào WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.X, cũng kiểm tra các kế hoạch thực hiện. Mặc dù đôi khi có thể hack kế hoạch để có được một ống chỉ. Có một mục kết nối yêu cầu một gợi ý cho việc này.
Martin Smith

16

Các câu trả lời được chấp nhận ở đây nói "một CTE không bao giờ nên được sử dụng để thực hiện" - nhưng điều đó có thể gây nhầm lẫn. Trong ngữ cảnh của các CTE so với các bảng tạm thời, tôi vừa hoàn thành việc loại bỏ một đống rác khỏi một bộ procs được lưu trữ bởi vì một số doofus phải nghĩ rằng có rất ít hoặc không có chi phí sử dụng bảng tạm thời. Tôi đã chuyển rất nhiều vào CTE, ngoại trừ những thứ hợp pháp sẽ được sử dụng lại trong suốt quá trình. Tôi đã đạt được hiệu suất khoảng 20% ​​bởi tất cả các số liệu. Sau đó tôi bắt đầu loại bỏ tất cả các con trỏ đang cố gắng thực hiện xử lý đệ quy. Đây là nơi tôi thấy lợi ích lớn nhất. Tôi đã kết thúc thời gian phản ứng cắt giảm bởi một yếu tố mười.

CTE và bảng tạm thời có trường hợp sử dụng rất khác nhau. Tôi chỉ muốn nhấn mạnh rằng, mặc dù không phải là thuốc chữa bách bệnh, việc hiểu và sử dụng đúng CTE có thể dẫn đến một số cải tiến thực sự về cả chất lượng / khả năng bảo trì và tốc độ mã. Vì tôi đã xử lý chúng, tôi thấy các bảng tạm thời và các con trỏ là những tệ nạn lớn của xử lý SQL. Tôi có thể nhận được bằng cách tốt với các biến bảng và CTE cho hầu hết mọi thứ bây giờ. Mã của tôi sạch hơn và nhanh hơn.


Bây giờ, hãy công bằng - con trỏ là ác quỷ lớn ; bảng tạm thời là tồi tệ nhất một cái ác ít hơn . :-) Đó là thực sự không công bằng để đặt chúng cùng cấp, như bạn đã thấy chính mình.
RDFozz

@RDFozz đúng, địa ngục có 9 vòng tròn như chúng ta đều biết . Hãy đặt bảng tạm thời ở vị trí thứ 2 và con trỏ ở ... thứ 7? ;)
ypercubeᵀᴹ

1
Bạn có biết 'ác lớn' trong lập trình là gì không? Khi mọi người nói rằng một kỹ thuật cụ thể là xấu xa. Có một nơi cho con trỏ. Họ có thể vượt trội hơn các kỹ thuật khác trong các kịch bản nhất định. Không có gì xấu ở đây - bạn cần học cách sử dụng công cụ phù hợp cho công việc. Đo lường những gì bạn đang làm và đừng tin sự cường điệu rằng CTE, Temp Table hoặc Cursors là xấu xa. Đo lường - bởi vì sự thật phụ thuộc vào kịch bản.
Dave Hilditch

@DaveHilditch đó là một nhận xét công bằng, nhưng cũng là nhận xét công bằng để khẳng định rằng trong rất, rất nhiều tình huống, con trỏ không phải là giải pháp phù hợp, vì vậy đây là một khái quát khả thi để có chúng, gần như là phương sách cuối cùng.
Mel Padden

1
Theo kinh nghiệm của tôi, bản thân nó không tệ. HIỆN TẠI thường được các nhà phát triển sử dụng "sai" bởi vì trong hầu hết các ngôn ngữ lập trình, bạn phải suy nghĩ lặp đi lặp lại, trái ngược với SQL, nơi bạn chủ yếu phải suy nghĩ theo đợt. Tôi biết đây là một lỗi phổ biến tại nơi làm việc của tôi, nơi Devs không thể "nhìn thấy" một cách giải quyết vấn đề nào khác ngoài HIỆN TẠI, vì vậy tại sao một DBA tốt lại có ích để dạy và sửa chúng. @DaveHilditch hoàn toàn đúng: công cụ phù hợp cho công việc phù hợp là tất cả những gì nó cần.
Philippe

14

Một CTE có thể được gọi nhiều lần trong một truy vấn và được đánh giá mỗi khi nó được tham chiếu - quá trình này có thể được đệ quy. Nếu nó chỉ được gọi một lần thì nó hoạt động giống như một truy vấn phụ, mặc dù các CTE có thể được tham số hóa.

Một bảng tạm thời vẫn tồn tại về mặt vật lý và có thể được lập chỉ mục. Trong thực tế, trình tối ưu hóa truy vấn cũng có thể duy trì các kết quả truy vấn trung gian hoặc truy vấn phụ phía sau hậu trường, chẳng hạn như trong các hoạt động của bộ đệm, do đó không đúng khi các kết quả của CTE không bao giờ được lưu vào đĩa.

Các biến của bảng IIRC (mặt khác) luôn là các cấu trúc trong bộ nhớ.


4
CTE có thể được tham số hóa? Làm sao? Ngoài ra, các biến bảng không phải luôn luôn trong cấu trúc bộ nhớ. Xem câu trả lời tuyệt vời của Martin cho một câu hỏi liên quan.
Paul White

11

Bảng tạm thời là một đối tượng thực trong tempdb, nhưng cte chỉ là một loại trình bao bọc xung quanh truy vấn phức tạp để đơn giản hóa cú pháp tổ chức đệ quy trong một bước.


8

Lý do chính để sử dụng CTE là để truy cập các Hàm cửa sổ như row_number()và nhiều chức năng khác.

Điều này có nghĩa là bạn có thể thực hiện những việc như lấy hàng đầu tiên hoặc cuối cùng cho mỗi nhóm RẤT RẤT nhanh chóng và hiệu quả - hiệu quả hơn các phương tiện khác trong hầu hết các trường hợp thực tế .

with reallyfastcte as (
select *, 
row_number() over (partition by groupingcolumn order by sortingcolumn) as rownum
from sometable
)
select *
from reallyfastcte
where rownum = 1;

Bạn có thể chạy một truy vấn tương tự như trên bằng cách sử dụng truy vấn con tương quan hoặc bằng cách sử dụng truy vấn phụ nhưng CTE sẽ nhanh hơn trong hầu hết các kịch bản.

Ngoài ra, CTE thực sự có thể giúp đơn giản hóa mã của bạn. Điều này có thể dẫn đến tăng hiệu suất vì bạn hiểu truy vấn nhiều hơn và có thể giới thiệu logic kinh doanh nhiều hơn để giúp trình tối ưu hóa được lựa chọn nhiều hơn.

Ngoài ra, CTE có thể tăng hiệu suất nếu bạn hiểu logic kinh doanh của mình và biết phần nào của truy vấn sẽ được chạy trước - thông thường, đặt các truy vấn chọn lọc nhất của bạn trước dẫn đến các tập kết quả có thể sử dụng chỉ mục trong lần nối tiếp theo của chúng và thêm option(force order)truy vấn dấu

Cuối cùng, các CTE không sử dụng tempdb theo mặc định để bạn giảm sự tranh chấp về nút cổ chai đó thông qua việc sử dụng chúng.

Nên sử dụng các bảng tạm thời nếu bạn cần truy vấn dữ liệu nhiều lần hoặc cách khác nếu bạn đo các truy vấn của mình và khám phá điều đó bằng cách chèn vào bảng tạm thời và sau đó thêm một chỉ mục mà hiệu suất của bạn được cải thiện.


tất cả các điểm tốt ... +1
Mel Padden

6

Dường như có một chút tiêu cực ở đây đối với CTE.

Sự hiểu biết của tôi về CTE là về cơ bản nó là một dạng xem adhoc. SQL là cả một ngôn ngữ dựa trên khai báo và tập hợp. CTE là một cách tuyệt vời để khai báo một bộ! Không thể lập chỉ mục CTE thực sự là một điều tốt vì bạn không cần! Nó thực sự là một loại đường cú pháp để làm cho truy vấn dễ đọc / ghi hơn. Bất kỳ trình tối ưu hóa tốt nào cũng sẽ có kế hoạch truy cập tốt nhất bằng cách sử dụng các chỉ mục trên các bảng bên dưới. Điều này có nghĩa là bạn có thể tăng tốc truy vấn CTE của mình một cách hiệu quả bằng cách làm theo lời khuyên về chỉ mục trên các bảng bên dưới.

Ngoài ra, chỉ vì bạn đã xác định một bộ là CTE, điều đó không có nghĩa là tất cả các hàng trong bộ phải được xử lý. Phụ thuộc vào truy vấn, trình tối ưu hóa có thể xử lý các hàng "vừa đủ" để đáp ứng truy vấn. Có lẽ bạn chỉ cần 20 hoặc hơn cho màn hình của bạn. Nếu bạn đã xây dựng một bảng tạm thời thì bạn thực sự cần phải đọc / ghi tất cả các hàng đó!

Dựa trên điều này tôi sẽ nói rằng CTE là một tính năng tuyệt vời của SQL và có thể được sử dụng ở bất cứ đâu mà chúng làm cho truy vấn dễ đọc hơn. Tôi sẽ chỉ nghĩ về một bảng tạm thời cho một quy trình hàng loạt thực sự cần xử lý mỗi bản ghi. Ngay cả sau đó, nó không thực sự được khuyến khích bởi vì trên bảng tạm thời, cơ sở dữ liệu sẽ khó hơn rất nhiều để giúp bạn lưu trữ và lập chỉ mục. Có thể tốt hơn nếu có một bảng cố định với trường PK duy nhất cho giao dịch của bạn.

Tôi phải thừa nhận rằng trải nghiệm của tôi chủ yếu là với DB2 vì vậy tôi cho rằng CTE hoạt động theo cách tương tự trong cả hai sản phẩm. Tôi sẽ vui vẻ đứng ra sửa nếu CTE bằng cách nào đó kém hơn trong máy chủ SQL. ;)

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.