Câu hỏi của bạn cho thấy bạn đã chịu thua một số quan niệm sai lầm phổ biến xung quanh các biến bảng và bảng tạm thời.
Tôi đã viết một câu trả lời khá rộng rãi trên trang DBA xem xét sự khác biệt giữa hai loại đối tượng. Điều này cũng giải quyết câu hỏi của bạn về đĩa so với bộ nhớ (Tôi không thấy bất kỳ sự khác biệt đáng kể nào trong hành vi giữa hai người).
Về câu hỏi trong tiêu đề mặc dù khi nào nên sử dụng biến bảng so với bảng tạm thời cục bộ, bạn không phải luôn có lựa chọn. Ví dụ, trong các hàm, chỉ có thể sử dụng biến bảng và nếu bạn cần ghi vào bảng trong phạm vi con thì chỉ có một #temp
bảng sẽ làm (các tham số có giá trị bảng cho phép truy cập chỉ đọc ).
Trường hợp bạn có một sự lựa chọn, một số gợi ý dưới đây (mặc dù phương pháp đáng tin cậy nhất là chỉ cần kiểm tra cả hai với khối lượng công việc cụ thể của bạn).
Nếu bạn cần một chỉ mục không thể được tạo trên một biến bảng thì tất nhiên bạn sẽ cần một #temporary
bảng. Các chi tiết của điều này là phụ thuộc phiên bản tuy nhiên. Đối với SQL Server 2012 và thấp hơn các chỉ mục duy nhất có thể được tạo trên các biến của bảng là những chỉ mục được tạo ngầm thông qua một UNIQUE
hoặc PRIMARY KEY
ràng buộc. SQL Server 2014 đã giới thiệu cú pháp chỉ mục nội tuyến cho một tập hợp con các tùy chọn có sẵn trong CREATE INDEX
. Điều này đã được mở rộng kể từ khi cho phép các điều kiện chỉ mục được lọc. Tuy nhiên, các chỉ mục có INCLUDE
cột -d hoặc chỉ mục của cột vẫn không thể tạo trên các biến của bảng.
Nếu bạn sẽ liên tục thêm và xóa số lượng lớn các hàng khỏi bảng thì hãy sử dụng #temporary
bảng. Điều đó hỗ trợ TRUNCATE
(hiệu quả hơn so DELETE
với các bảng lớn) và các lần chèn tiếp theo sau TRUNCATE
có thể có hiệu suất tốt hơn so với các bảng theo sau DELETE
như được minh họa ở đây .
- Nếu bạn sẽ xóa hoặc cập nhật một số lượng lớn các hàng thì bảng tạm thời có thể hoạt động tốt hơn nhiều so với biến bảng - nếu nó có thể sử dụng chia sẻ hàng (ví dụ: "Hiệu ứng chia sẻ hàng" bên dưới).
- Nếu kế hoạch tối ưu sử dụng bảng sẽ thay đổi tùy thuộc vào dữ liệu thì hãy sử dụng
#temporary
bảng. Điều đó hỗ trợ tạo số liệu thống kê cho phép kế hoạch được biên dịch lại theo dữ liệu (mặc dù đối với các bảng tạm thời được lưu trong bộ nhớ cache trong quy trình lưu trữ , hành vi biên dịch lại cần được hiểu riêng).
- Nếu kế hoạch tối ưu cho truy vấn sử dụng bảng không có khả năng thay đổi thì bạn có thể xem xét một biến bảng để bỏ qua chi phí tạo và biên dịch lại thống kê (có thể yêu cầu gợi ý để sửa gói bạn muốn).
- Nếu nguồn cho dữ liệu được chèn vào bảng là từ một
SELECT
câu lệnh có khả năng đắt tiền thì hãy xem xét rằng việc sử dụng biến bảng sẽ chặn khả năng này bằng cách sử dụng một kế hoạch song song.
- Nếu bạn cần dữ liệu trong bảng để tồn tại trong quá trình quay lại giao dịch người dùng bên ngoài thì hãy sử dụng biến bảng. Một trường hợp sử dụng có thể cho việc này có thể là ghi nhật ký tiến trình của các bước khác nhau trong một lô SQL dài.
- Khi sử dụng
#temp
bảng trong khóa giao dịch người dùng có thể được giữ lâu hơn so với biến bảng (có thể cho đến khi kết thúc giao dịch so với kết thúc câu lệnh phụ thuộc vào loại khóa và mức cô lập) và cũng có thể ngăn chặn việc cắt giảm tempdb
nhật ký giao dịch cho đến khi giao dịch người dùng kết thúc. Vì vậy, điều này có thể ủng hộ việc sử dụng các biến bảng.
- Trong các thói quen được lưu trữ, cả hai biến bảng và bảng tạm thời có thể được lưu trữ. Việc bảo trì siêu dữ liệu cho các biến của bảng được lưu trong bộ nhớ cache ít hơn so với
#temporary
các bảng. Bob Ward chỉ ra trong tempdb
bài trình bày của mình rằng điều này có thể gây ra sự tranh chấp bổ sung trên các bảng hệ thống trong điều kiện đồng thời cao. Ngoài ra, khi xử lý một lượng nhỏ dữ liệu, điều này có thể tạo ra sự khác biệt có thể đo lường được đối với hiệu suất .
Tác dụng của việc chia sẻ hàng
DECLARE @T TABLE(id INT PRIMARY KEY, Flag BIT);
CREATE TABLE #T (id INT PRIMARY KEY, Flag BIT);
INSERT INTO @T
output inserted.* into #T
SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY @@SPID), 0
FROM master..spt_values v1, master..spt_values v2
SET STATISTICS TIME ON
/*CPU time = 7016 ms, elapsed time = 7860 ms.*/
UPDATE @T SET Flag=1;
/*CPU time = 6234 ms, elapsed time = 7236 ms.*/
DELETE FROM @T
/* CPU time = 828 ms, elapsed time = 1120 ms.*/
UPDATE #T SET Flag=1;
/*CPU time = 672 ms, elapsed time = 980 ms.*/
DELETE FROM #T
DROP TABLE #T
tempDB
- rằng "trong bộ nhớ" là một huyền thoại. Ngoài ra: các biến của bảng sẽ luôn được trình tối ưu hóa truy vấn xem xét để giữ chính xác một hàng - nếu bạn có nhiều hơn, điều này có thể dẫn đến các kế hoạch thực hiện tồi tệ.