Đó là nhiều biểu diễn, CTE hoặc bảng tạm thời?


Câu trả lời:


62

Tôi muốn nói rằng chúng là những khái niệm khác nhau nhưng không quá khác nhau để nói "phấn và phô mai".

  • Một bảng tạm thời là tốt để sử dụng lại hoặc để thực hiện nhiều lần xử lý trên một tập hợp dữ liệu.

  • Một CTE có thể được sử dụng để tái diễn hoặc đơn giản là cải thiện khả năng đọc.
    Và, như một khung nhìn hoặc hàm nội tuyến có giá trị cũng có thể được coi như một macro được mở rộng trong truy vấn chính

  • Một bảng tạm thời là một bảng khác với một số quy tắc xung quanh phạm vi

Tôi đã lưu trữ procs nơi tôi sử dụng cả hai (và cả biến bảng)


12
Bảng tạm thời cũng cho phép Lập chỉ mục và thậm chí Thống kê đôi khi cần thiết, trong khi CTE thì không.
CodeCowboyOrg

9
Tôi nghĩ rằng câu trả lời này không đủ làm nổi bật thực tế rằng CTE có thể dẫn đến hiệu suất khủng khiếp. Tôi thường đề cập đến câu trả lời này trên dba.stackexchange. Câu hỏi của bạn xuất hiện thứ hai trong công cụ tìm kiếm của tôi nếu tôi đang tìm kiếm cte vs temporary tablesvì vậy IMHO câu trả lời này cần làm nổi bật những nhược điểm của CTE. TL; DR của câu trả lời được liên kết: không bao giờ nên sử dụng CTE cho hiệu suất. . Tôi đồng ý với trích dẫn đó vì tôi đã trải qua những nhược điểm của CTE.
TT.

2
@TT. Hấp dẫn. Tôi thấy rằng CTE hoạt động tốt hơn nhiều
Squ1rr3lz

197

Nó phụ thuộc.

Đầu tiên

Biểu thức bảng chung là gì?

CTE (không đệ quy) được xử lý rất giống với các cấu trúc khác cũng có thể được sử dụng làm biểu thức bảng nội tuyến trong SQL Server. Các bảng có nguồn gốc, dạng xem và hàm nội tuyến có giá trị. Lưu ý rằng trong khi BOL nói rằng CTE "có thể được coi là tập kết quả tạm thời" thì đây là một mô tả hoàn toàn hợp lý. Thường xuyên hơn không, nó không phải là vật chất của chính nó.

Một bảng tạm thời là gì?

Đây là một tập hợp các hàng được lưu trữ trên các trang dữ liệu trong tempdb. Các trang dữ liệu có thể nằm một phần hoặc toàn bộ trong bộ nhớ. Ngoài ra, bảng tạm thời có thể được lập chỉ mục và có số liệu thống kê cột.

Kiểm tra dữ liệu

CREATE TABLE T(A INT IDENTITY PRIMARY KEY, B INT , F CHAR(8000) NULL);

INSERT INTO T(B)
SELECT TOP (1000000)  0 + CAST(NEWID() AS BINARY(4))
FROM master..spt_values v1,
     master..spt_values v2;

ví dụ 1

WITH CTE1 AS
(
SELECT A,
       ABS(B) AS Abs_B,
       F
FROM T
)
SELECT *
FROM CTE1
WHERE A = 780

Kế hoạch 1

Lưu ý trong kế hoạch trên không có đề cập đến CTE1. Nó chỉ truy cập trực tiếp vào các bảng cơ sở và được xử lý giống như

SELECT A,
       ABS(B) AS Abs_B,
       F
FROM   T
WHERE  A = 780 

Viết lại bằng cách cụ thể hóa CTE thành một bảng tạm thời trung gian ở đây sẽ phản tác dụng ồ ạt.

Cụ thể hóa định nghĩa CTE của

SELECT A,
       ABS(B) AS Abs_B,
       F
FROM T

Sẽ liên quan đến việc sao chép khoảng 8GB dữ liệu vào một bảng tạm thời, sau đó vẫn còn chi phí lựa chọn từ đó.

Ví dụ 2

WITH CTE2
     AS (SELECT *,
                ROW_NUMBER() OVER (ORDER BY A) AS RN
         FROM   T
         WHERE  B % 100000 = 0)
SELECT *
FROM   CTE2 T1
       CROSS APPLY (SELECT TOP (1) *
                    FROM   CTE2 T2
                    WHERE  T2.A > T1.A
                    ORDER  BY T2.A) CA 

Ví dụ trên mất khoảng 4 phút trên máy của tôi.

Chỉ có 15 hàng trong số 1.000.000 giá trị được tạo ngẫu nhiên khớp với vị từ nhưng việc quét bảng đắt tiền xảy ra 16 lần để xác định vị trí này.

nhập mô tả hình ảnh ở đây

Đây sẽ là một ứng cử viên tốt để cụ thể hóa kết quả trung gian. Việc viết lại bảng tạm thời tương đương mất 25 giây.

INSERT INTO #T
SELECT *,
       ROW_NUMBER() OVER (ORDER BY A) AS RN
FROM   T
WHERE  B % 100000 = 0

SELECT *
FROM   #T T1
       CROSS APPLY (SELECT TOP (1) *
                    FROM   #T T2
                    WHERE  T2.A > T1.A
                    ORDER  BY T2.A) CA 

Với kế hoạch

Việc cụ thể hóa trung gian một phần của truy vấn vào bảng tạm thời đôi khi có thể hữu ích ngay cả khi nó chỉ được đánh giá một lần - khi nó cho phép phần còn lại của truy vấn được biên dịch lại, tận dụng các số liệu thống kê về kết quả cụ thể hóa. Một ví dụ về cách tiếp cận này là trong bài viết SQL Cat Khi phá vỡ các truy vấn phức tạp .

Trong một số trường hợp, SQL Server sẽ sử dụng một bộ đệm để lưu trữ một kết quả trung gian, ví dụ như CTE và tránh phải đánh giá lại cây con đó. Điều này được thảo luận trong mục Kết nối (di chuyển) Cung cấp một gợi ý để buộc vật chất hóa trung gian của CTE hoặc các bảng dẫn xuất . Tuy nhiên, không có số liệu thống kê nào được tạo ra về điều này và ngay cả khi số lượng các hàng được lưu trữ khác biệt nhiều so với ước tính thì không thể thực hiện kế hoạch thực hiện tiến trình để thích ứng linh hoạt trong phản ứng (ít nhất là trong các phiên bản hiện tại. tương lai).


33
Đây là câu trả lời duy nhất trả lời cho câu hỏi thực tế (câu hỏi nào có hiệu suất tốt hơn không phải là sự khác biệt hoặc điều bạn thích) và nó trả lời đúng câu hỏi đó: "Nó phụ thuộc" là câu trả lời đúng. Đây cũng là câu trả lời duy nhất với dữ liệu hỗ trợ để giải thích, một số người khác (có số phiếu bầu cao) đưa ra tuyên bố chắc chắn rằng cái này tốt hơn cái kia không có tài liệu tham khảo hoặc bằng chứng ... Rõ ràng, tất cả những câu trả lời đó cũng sai . Bởi vì "Nó phụ thuộc"
Arkaine55 6/07/2015

2
Nó cũng là một câu trả lời tốt bằng văn bản, tham khảo tốt. Nghiêm túc đỉnh cao.
Dan Williams

50

CTE có công dụng của nó - khi dữ liệu trong CTE nhỏ và có sự cải thiện khả năng đọc mạnh mẽ như với trường hợp trong các bảng đệ quy. Tuy nhiên, hiệu suất của nó chắc chắn không tốt hơn các biến của bảng và khi một người đang xử lý các bảng rất lớn, các bảng tạm thời vượt trội hơn đáng kể so với CTE. Điều này là do bạn không thể xác định các chỉ mục trên CTE và khi bạn có lượng dữ liệu lớn yêu cầu tham gia với một bảng khác (CTE đơn giản giống như một macro). Nếu bạn đang tham gia nhiều bảng với hàng triệu bản ghi trong mỗi bảng, CTE sẽ hoạt động kém hơn đáng kể so với các bảng tạm thời.


9
Tôi đã nhìn thấy điều này từ kinh nghiệm của riêng tôi. CTE thực hiện chậm hơn đáng kể.
goku_da_master

7
CTE cũng hoạt động chậm hơn vì kết quả không được lưu trong bộ nhớ cache. Vì vậy, mỗi khi bạn sử dụng CTE, nó sẽ chạy lại truy vấn, kế hoạch và tất cả.
goku_da_master

1
Và công cụ db có thể chọn chạy lại truy vấn không chỉ mỗi tham chiếu, mà đối với mỗi hàng của truy vấn người tiêu dùng, như một truy vấn con tương quan ... bạn phải luôn luôn đề phòng điều đó nếu không mong muốn.
Mike M

Bảng tạm thời được lưu trữ trong tempdb trên SQL Server, đây là đĩa nhưng có lợi ích là được lập chỉ mục và trình tối ưu hóa SQL hoạt động tốt trên các truy vấn được chọn trong trường hợp đó. Không chắc chắn về vùng db hoặc vùng đĩa mà CTE được lưu trữ (khi nó vượt quá kích thước bộ nhớ và được xếp hàng để phân trang IO) nhưng nó không bao giờ được tối ưu hóa với khối lượng dữ liệu lớn. Đôi khi tôi đã sử dụng tùy chọn trình biên dịch (với biên dịch lại) để làm cho nó nhanh hơn
rmehra76

33

Các bảng tạm thời luôn ở trên đĩa - miễn là CTE của bạn có thể được giữ trong bộ nhớ, rất có thể nó sẽ nhanh hơn (giống như một biến bảng).

Nhưng một lần nữa, nếu tải dữ liệu của CTE (hoặc biến bảng tạm thời) của bạn quá lớn, nó cũng sẽ được lưu trữ trên đĩa, do đó không có lợi ích lớn.

Nói chung, tôi thích CTE hơn bảng tạm thời vì nó đã biến mất sau khi tôi sử dụng nó. Tôi không cần phải suy nghĩ về việc bỏ nó một cách rõ ràng hay bất cứ điều gì.

Vì vậy, cuối cùng không có câu trả lời rõ ràng, nhưng cá nhân tôi, tôi thích CTE hơn các bảng tạm thời.


2
Trong trường hợp SQLite và PostgreSQL, các bảng tạm thời sẽ tự động bị hủy (thường là vào cuối phiên). Tôi không biết về DBMS khác mặc dù.
Serrano

1
CTE giống như một cái nhìn tạm thời. Dữ liệu AFAIK không được lưu trữ nên không có gì được lưu trong bộ nhớ hoặc được lưu trên đĩa. Lưu ý quan trọng, mỗi khi bạn sử dụng CTE, truy vấn sẽ chạy lại.
Cướp

1
Cá nhân tôi chưa bao giờ thấy CTE hoạt động tốt hơn bảng Temp về tốc độ. Và gỡ lỗi cũng dễ dàng hơn nhiều với bảng tạm thời
Mark Monforti

7

Vì vậy, truy vấn tôi được chỉ định để tối ưu hóa được viết bằng hai CTE trong máy chủ SQL. Mất 28 giây.

Tôi đã dành hai phút để chuyển đổi chúng thành các bảng tạm thời và truy vấn mất 3 giây

Tôi đã thêm một chỉ mục vào bảng tạm thời trên trường mà nó đang được tham gia và giảm xuống còn 2 giây

Ba phút làm việc và bây giờ nó chạy nhanh hơn 12 lần bằng cách loại bỏ CTE. Cá nhân tôi sẽ không sử dụng CTE bao giờ họ cũng khó gỡ lỗi hơn.

Điều điên rồ là các CTE đều chỉ được sử dụng một lần và vẫn đưa ra một chỉ số cho chúng nhanh hơn 50%.


6

CTE sẽ không chiếm bất kỳ không gian vật lý nào. Nó chỉ là một tập kết quả chúng ta có thể sử dụng tham gia.

Bảng tạm thời là tạm thời. Chúng ta có thể tạo các chỉ mục, các ràng buộc như các bảng thông thường mà chúng ta cần xác định tất cả các biến.

Phạm vi của bảng tạm thời chỉ trong phiên. EX: Mở hai cửa sổ truy vấn SQL

create table #temp(empid int,empname varchar)
insert into #temp 
select 101,'xxx'

select * from #temp

Chạy truy vấn này trong cửa sổ đầu tiên, sau đó chạy truy vấn bên dưới trong cửa sổ thứ hai, bạn có thể tìm thấy sự khác biệt.

select * from #temp

4
>> "nó chỉ là một tập kết quả mà chúng ta có thể sử dụng tham gia." -> Điều này không chính xác. CTE không phải là "tập kết quả" mà là mã nội tuyến. Công cụ truy vấn SQL Server phân tích mã CTE như một phần của văn bản truy vấn và xây dựng kế hoạch thực hiện theo. Ý tưởng rằng CTE là nội tuyến là lợi thế lớn của việc sử dụng CTE, vì nó cho phép máy chủ tạo ra một "kế hoạch thực hiện kết hợp"
Ronen Ariely

4

Tôi đã sử dụng cả hai nhưng trong các quy trình phức tạp lớn luôn tìm thấy các bảng tạm thời tốt hơn để làm việc và có phương pháp hơn. CTE có công dụng của chúng nhưng nhìn chung với dữ liệu nhỏ.

Ví dụ: tôi đã tạo các sprocs quay lại với kết quả tính toán lớn trong 15 giây nhưng chuyển đổi mã này để chạy trong CTE và đã thấy nó chạy quá 8 phút để đạt được kết quả tương tự.


3

Đến bữa tiệc muộn, nhưng ...

Môi trường tôi làm việc rất hạn chế, hỗ trợ một số sản phẩm của nhà cung cấp và cung cấp các dịch vụ "giá trị gia tăng" như báo cáo. Do các hạn chế về chính sách và hợp đồng, tôi thường không cho phép sự xa xỉ của không gian dữ liệu / bảng riêng biệt và / hoặc khả năng tạo mã vĩnh viễn [nó sẽ tốt hơn một chút, tùy thuộc vào ứng dụng].

IOW, tôi thường không thể phát triển một thủ tục được lưu trữ hoặc UDFs hoặc bảng tạm thời, v.v. Tôi gần như phải làm mọi thứ thông qua giao diện ứng dụng MY (Báo cáo Crystal - bảng thêm / liên kết, đặt các mệnh đề từ w / in CR, v.v. ). Một ân huệ tiết kiệm nhỏ là Crystal cho phép tôi sử dụng LỰA CHỌN (cũng như Biểu thức SQL). Một số điều không hiệu quả thông qua khả năng bảng add / link thông thường có thể được thực hiện bằng cách xác định Lệnh SQL. Tôi sử dụng CTE thông qua đó và đã nhận được kết quả rất tốt "từ xa". CTE cũng giúp w / báo cáo bảo trì, không yêu cầu phát triển mã, giao cho DBA để biên dịch, mã hóa, chuyển, cài đặt và sau đó yêu cầu thử nghiệm nhiều cấp độ. Tôi có thể làm CTE thông qua giao diện cục bộ.

Mặt trái của việc sử dụng CTE w / CR là, mỗi báo cáo là riêng biệt. Mỗi CTE phải được duy trì cho mỗi báo cáo. Khi tôi có thể thực hiện SP và UDF, tôi có thể phát triển thứ gì đó có thể được sử dụng bởi nhiều báo cáo, chỉ yêu cầu liên kết với SP và truyền tham số như thể bạn đang làm việc trên một bảng thông thường. CR không thực sự tốt trong việc xử lý các tham số vào các Lệnh SQL, do đó khía cạnh của khía cạnh CR / CTE có thể thiếu. Trong những trường hợp đó, tôi thường cố gắng xác định CTE để trả về đủ dữ liệu (nhưng không phải TẤT CẢ dữ liệu), sau đó sử dụng các khả năng chọn bản ghi trong CR để cắt và xúc xắc.

Vì vậy, ... phiếu bầu của tôi là dành cho CTE (cho đến khi tôi có được không gian dữ liệu của mình).


3

Một cách sử dụng mà tôi thấy hiệu suất vượt trội của CTE là ở chỗ tôi cần tham gia Truy vấn tương đối phức tạp vào một vài bảng có vài triệu hàng mỗi bảng.

Trước tiên, tôi đã sử dụng CTE để chọn tập hợp con dựa trên các cột được lập chỉ mục để trước tiên cắt các bảng này xuống còn vài nghìn hàng có liên quan và sau đó nối CTE vào truy vấn chính của tôi. Điều này giảm theo cấp số nhân thời gian chạy truy vấn của tôi.

Trong khi kết quả cho CTE không được lưu trong bộ nhớ cache và các biến bảng có thể là lựa chọn tốt hơn, tôi thực sự chỉ muốn dùng thử và tìm thấy sự phù hợp với kịch bản trên.


Ngoài ra, tôi nghĩ vì tôi chỉ sử dụng CTE trong tham gia nên tôi chỉ thực sự thực hiện CTE một lần trong truy vấn của mình nên lưu trữ kết quả không phải là vấn đề lớn về mặt này
mua

1

Đây là một câu hỏi kết thúc thực sự mở và tất cả phụ thuộc vào cách sử dụng và loại bảng tạm thời (Biến bảng hoặc bảng truyền thống).

Một bảng tạm thời truyền thống lưu trữ dữ liệu trong DB tạm thời, làm chậm các bảng tạm thời; tuy nhiên các biến bảng không.


1

Tôi vừa thử nghiệm điều này - cả CTE và không CTE (trong đó truy vấn được gõ cho mọi trường hợp liên kết) cả hai mất ~ 31 giây. CTE làm cho mã dễ đọc hơn nhiều - cắt giảm từ 241 xuống 130 dòng rất đẹp. Mặt khác, bảng Temp đã cắt nó xuống còn 132 dòng và lấy FIVE GIÂY để chạy. Không phải trò đùa. tất cả các thử nghiệm này đã được lưu trữ - các truy vấn đều được chạy nhiều lần trước đó.


1

Từ kinh nghiệm của tôi trong SQL Server, tôi đã tìm thấy một trong những tình huống trong đó CTE vượt trội hơn bảng Temp

Tôi cần sử dụng Bộ dữ liệu (~ 100000) từ Truy vấn phức tạp chỉ ONCE trong Quy trình được lưu trữ của tôi.

  • Bảng tạm thời gây ra tình trạng quá tải trên SQL khi Quy trình của tôi hoạt động chậm (vì Bảng tạm thời là các bảng được vật chất hóa thực sự tồn tại trong tempdb và Kiên trì cho quy trình hiện tại của tôi)

  • Mặt khác, với CTE, CTE Chỉ tồn tại cho đến khi truy vấn sau được chạy. Vì vậy, CTE là một cấu trúc trong bộ nhớ tiện dụng với Phạm vi hạn chế. CTE không sử dụng tempdb theo mặc định.

Đây là một kịch bản trong đó các CTE thực sự có thể giúp đơn giản hóa mã của bạn và vượt trội hơn Bảng tạm thời. Tôi đã sử dụng 2 CTE, đại loại như

WITH CTE1(ID, Name, Display) 
AS (SELECT ID,Name,Display from Table1 where <Some Condition>),
CTE2(ID,Name,<col3>) AS (SELECT ID, Name,<> FROM CTE1 INNER JOIN Table2 <Some Condition>)
SELECT CTE2.ID,CTE2.<col3>
FROM CTE2
GO

1
Câu trả lời của bạn dường như rất chung chung ... Làm thế nào để bạn đo được rằng "CTE vượt trội hơn bảng Temp"? Bạn đã có một số đo thời gian? Theo tôi bạn nên chỉnh sửa câu trả lời của bạn và thêm chi tiết.
Il Vic

Có, tôi có các phép đo thời gian và kế hoạch Thi hành để hỗ trợ cho tuyên bố của mình.
Amardeep Kohli

Không thể thêm img cho kế hoạch thực hiện vì các đặc quyền hạn chế. Sẽ cập nhật chi tiết một khi nó được giải quyết
Amardeep Kohli
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.