Sự khác biệt giữa bảng tạm thời và biến bảng trong SQL Server là gì?


390

Trong SQL Server 2005, chúng ta có thể tạo các bảng tạm thời theo một trong hai cách:

declare @tmp table (Col1 int, Col2 int);

hoặc là

create table #tmp (Col1 int, Col2 int);

Sự khác biệt giữa hai là gì? Tôi đã đọc các ý kiến ​​trái ngược nhau về việc @tmp vẫn sử dụng tempdb hay nếu mọi thứ xảy ra trong bộ nhớ.

Trong những kịch bản nào người này thực hiện khác?



2
Có một bài viết thực sự hay của Pinal Dave tại đây ... blog.sqlauthority.com/2009/12/15/iêu
sam yi

Câu trả lời:


392

Có một vài điểm khác biệt giữa Bảng tạm thời (#tmp) và Biến bảng (@tmp), mặc dù sử dụng tempdb không phải là một trong số chúng, như được đánh vần trong liên kết MSDN bên dưới.

Theo nguyên tắc thông thường, đối với khối lượng dữ liệu nhỏ đến trung bình và các tình huống sử dụng đơn giản, bạn nên sử dụng các biến bảng. (Đây là một hướng dẫn quá rộng với tất nhiên rất nhiều trường hợp ngoại lệ - xem bên dưới và các bài viết sau.)

Một số điểm cần xem xét khi lựa chọn giữa chúng:

  • Bảng tạm thời là các bảng thực để bạn có thể thực hiện những việc như CREATE INDEX, v.v. Nếu bạn có lượng dữ liệu lớn để truy cập theo chỉ mục sẽ nhanh hơn thì các bảng tạm thời là một lựa chọn tốt.

  • Các biến bảng có thể có các chỉ mục bằng cách sử dụng các ràng buộc PRIMARY KEY hoặc UNIQUE. (Nếu bạn muốn một chỉ mục không duy nhất, chỉ cần bao gồm cột khóa chính làm cột cuối cùng trong ràng buộc duy nhất. Nếu bạn không có một cột duy nhất, bạn có thể sử dụng một cột định danh.) SQL 2014 cũng có các chỉ mục không duy nhất .

  • Các biến bảng không tham gia vào các giao dịch và SELECTs được ngầm định với NOLOCK. Hành vi giao dịch có thể rất hữu ích, ví dụ nếu bạn muốn ROLLBACK giữa chừng trong một thủ tục thì các biến bảng được điền trong giao dịch đó sẽ vẫn được đưa vào!

  • Bảng tạm thời có thể dẫn đến các thủ tục lưu trữ được biên dịch lại, có lẽ thường xuyên. Bảng biến sẽ không.

  • Bạn có thể tạo bảng tạm thời bằng cách sử dụng CHỌN VÀO, có thể viết nhanh hơn (tốt cho truy vấn đặc biệt) và có thể cho phép bạn xử lý thay đổi kiểu dữ liệu theo thời gian, vì bạn không cần xác định trước cấu trúc bảng tạm thời.

  • Bạn có thể chuyển các biến bảng trở lại từ các hàm, cho phép bạn đóng gói và sử dụng lại logic dễ dàng hơn nhiều (ví dụ: tạo một hàm để tách một chuỗi thành một bảng các giá trị trên một số dấu phân cách tùy ý).

  • Sử dụng Biến bảng trong các hàm do người dùng xác định cho phép các hàm đó được sử dụng rộng rãi hơn (xem tài liệu TẠO CHỨC NĂNG để biết chi tiết). Nếu bạn đang viết một hàm, bạn nên sử dụng các biến bảng trên các bảng tạm thời trừ khi có nhu cầu hấp dẫn khác.

  • Cả hai biến bảng và bảng tạm thời được lưu trữ trong tempdb. Nhưng các biến bảng (từ năm 2005) mặc định đối chiếu cơ sở dữ liệu hiện tại so với các bảng tạm thời có đối chiếu mặc định của tempdb ( ref ). Điều này có nghĩa là bạn nên biết về các vấn đề đối chiếu nếu sử dụng bảng tạm thời và đối chiếu db của bạn khác với tempdb, gây ra sự cố nếu bạn muốn so sánh dữ liệu trong bảng tạm thời với dữ liệu trong cơ sở dữ liệu của mình.

  • Bảng tạm thời toàn cầu (## tmp) là một loại bảng tạm thời khác có sẵn cho tất cả các phiên và người dùng.

Một số đọc thêm:


26
Các biến bảng có thể có các chỉ mục. Chỉ cần tạo một ràng buộc duy nhất và bạn sẽ tự động nhận được một chỉ mục. Làm cho một sự khác biệt hiệu suất rất lớn. (Nếu bạn không muốn một chỉ mục duy nhất, chỉ cần thêm khóa chính thực tế vào cuối các trường bạn muốn. Nếu bạn chưa có chỉ mục, hãy tạo một cột nhận dạng).
Ben

7
@Ben Và SQL Server 2014 cho phép các chỉ mục không duy nhất được chỉ định trên các biến của bảng
Martin Smith

4
Các biến bảng không bị ảnh hưởng bởi các giao dịch đôi khi có ích. Nếu bạn có bất cứ thứ gì bạn muốn giữ lại sau khi quay lại, bạn có thể đặt nó vào một biến bảng.
quillbreaker

3
Thống kê được tạo cho các bảng tạm thời, có thể làm cho các kế hoạch truy vấn tốt hơn, nhưng không phải cho các biến bảng. Các thống kê này được lưu trong bộ nhớ cache trong một thời gian, cùng với các trang của bảng tạm thời, sau khi bảng tạm thời bị hủy và có thể không chính xác nếu bảng được lưu lại được kích hoạt lại.
Michael Green

Các biến của bảng sẽ mặc định là đối chiếu kiểu dữ liệu do người dùng định nghĩa (nếu cột là kiểu dữ liệu do người dùng xác định) hoặc đối chiếu của cơ sở dữ liệu hiện tại chứ không phải đối chiếu mặc định của tempdb. Các bảng tạm thời sẽ sử dụng đối chiếu mặc định tempdb. Xem: technet.microsoft.com/en-us/l
Library / ms188927.aspx

25

Chỉ cần nhìn vào yêu cầu trong câu trả lời được chấp nhận rằng các biến bảng không tham gia vào việc ghi nhật ký.

Nhìn chung có vẻ không đúng sự thật rằng có bất kỳ sự khác biệt nào về số lượng ghi nhật ký (ít nhất là cho insert/ update/ deletethao tác với chính bảng mặc dù tôi đã thấy rằng có một số khác biệt nhỏ về mặt này đối với các đối tượng tạm thời được lưu trong các thủ tục được lưu trữ do bảng hệ thống bổ sung cập nhật).

Tôi đã xem xét hành vi ghi nhật ký đối với cả a @table_variable#tempbảng cho các hoạt động sau.

  1. Chèn thành công
  2. Multi Row Chèn nơi câu lệnh được khôi phục do vi phạm ràng buộc.
  3. Cập nhật
  4. Xóa bỏ
  5. Giao dịch viên

Các bản ghi nhật ký giao dịch gần như giống hệt nhau cho tất cả các hoạt động.

Phiên bản biến bảng thực sự có một vài thêm các entry bản ghi vì nó được một mục thêm vào (và sau đó ra khỏi) các sys.syssingleobjrefsbảng cơ sở nhưng nhìn chung đã có một vài byte ít đăng nhập thuần túy như tên nội bộ cho bảng biến tiêu thụ 236 byte ít hơn so với #tempbảng (118 nvarcharký tự ít hơn ).

Kịch bản đầy đủ để tái tạo (chạy tốt nhất trên một phiên bản bắt đầu ở chế độ người dùng và sqlcmdchế độ sử dụng )

:setvar tablename "@T" 
:setvar tablescript "DECLARE @T TABLE"

/*
 --Uncomment this section to test a #temp table
:setvar tablename "#T" 
:setvar tablescript "CREATE TABLE #T"
*/

USE tempdb 
GO    
CHECKPOINT

DECLARE @LSN NVARCHAR(25)

SELECT @LSN = MAX([Current LSN])
FROM fn_dblog(null, null) 


EXEC(N'BEGIN TRAN StartBatch
SAVE TRAN StartBatch
COMMIT

$(tablescript)
(
[4CA996AC-C7E1-48B5-B48A-E721E7A435F0] INT PRIMARY KEY DEFAULT 0,
InRowFiller char(7000) DEFAULT ''A'',
OffRowFiller varchar(8000) DEFAULT REPLICATE(''B'',8000),
LOBFiller varchar(max) DEFAULT REPLICATE(cast(''C'' as varchar(max)),10000)
)


BEGIN TRAN InsertFirstRow
SAVE TRAN InsertFirstRow
COMMIT

INSERT INTO $(tablename)
DEFAULT VALUES

BEGIN TRAN Insert9Rows
SAVE TRAN Insert9Rows
COMMIT


INSERT INTO $(tablename) ([4CA996AC-C7E1-48B5-B48A-E721E7A435F0])
SELECT TOP 9 ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM sys.all_columns

BEGIN TRAN InsertFailure
SAVE TRAN InsertFailure
COMMIT


/*Try and Insert 10 rows, the 10th one will cause a constraint violation*/
BEGIN TRY
INSERT INTO $(tablename) ([4CA996AC-C7E1-48B5-B48A-E721E7A435F0])
SELECT TOP (10) (10 + ROW_NUMBER() OVER (ORDER BY (SELECT 0))) % 20
FROM sys.all_columns
END TRY
BEGIN CATCH
PRINT ERROR_MESSAGE()
END CATCH

BEGIN TRAN Update10Rows
SAVE TRAN Update10Rows
COMMIT

UPDATE $(tablename)
SET InRowFiller = LOWER(InRowFiller),
    OffRowFiller  =LOWER(OffRowFiller),
    LOBFiller  =LOWER(LOBFiller)


BEGIN TRAN Delete10Rows
SAVE TRAN Delete10Rows
COMMIT

DELETE FROM  $(tablename)
BEGIN TRAN AfterDelete
SAVE TRAN AfterDelete
COMMIT

BEGIN TRAN EndBatch
SAVE TRAN EndBatch
COMMIT')


DECLARE @LSN_HEX NVARCHAR(25) = 
        CAST(CAST(CONVERT(varbinary,SUBSTRING(@LSN, 1, 8),2) AS INT) AS VARCHAR) + ':' +
        CAST(CAST(CONVERT(varbinary,SUBSTRING(@LSN, 10, 8),2) AS INT) AS VARCHAR) + ':' +
        CAST(CAST(CONVERT(varbinary,SUBSTRING(@LSN, 19, 4),2) AS INT) AS VARCHAR)        

SELECT 
    [Operation],
    [Context],
    [AllocUnitName],
    [Transaction Name],
    [Description]
FROM   fn_dblog(@LSN_HEX, null) AS D
WHERE  [Current LSN] > @LSN  

SELECT CASE
         WHEN GROUPING(Operation) = 1 THEN 'Total'
         ELSE Operation
       END AS Operation,
       Context,
       AllocUnitName,
       COALESCE(SUM([Log Record Length]), 0) AS [Size in Bytes],
       COUNT(*)                              AS Cnt
FROM   fn_dblog(@LSN_HEX, null) AS D
WHERE  [Current LSN] > @LSN  
GROUP BY GROUPING SETS((Operation, Context, AllocUnitName),())

Các kết quả

+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
|                       |                    |                           |             @TV      |             #TV      |                  |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
| Operation             | Context            | AllocUnitName             | Size in Bytes | Cnt  | Size in Bytes | Cnt  | Difference Bytes |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
| LOP_ABORT_XACT        | LCX_NULL           |                           | 52            | 1    | 52            | 1    |                  |
| LOP_BEGIN_XACT        | LCX_NULL           |                           | 6056          | 50   | 6056          | 50   |                  |
| LOP_COMMIT_XACT       | LCX_NULL           |                           | 2548          | 49   | 2548          | 49   |                  |
| LOP_COUNT_DELTA       | LCX_CLUSTERED      | sys.sysallocunits.clust   | 624           | 3    | 624           | 3    |                  |
| LOP_COUNT_DELTA       | LCX_CLUSTERED      | sys.sysrowsets.clust      | 208           | 1    | 208           | 1    |                  |
| LOP_COUNT_DELTA       | LCX_CLUSTERED      | sys.sysrscols.clst        | 832           | 4    | 832           | 4    |                  |
| LOP_CREATE_ALLOCCHAIN | LCX_NULL           |                           | 120           | 3    | 120           | 3    |                  |
| LOP_DELETE_ROWS       | LCX_INDEX_INTERIOR | Unknown Alloc Unit        | 720           | 9    | 720           | 9    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysallocunits.clust   | 444           | 3    | 444           | 3    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysallocunits.nc      | 276           | 3    | 276           | 3    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.syscolpars.clst       | 628           | 4    | 628           | 4    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.syscolpars.nc         | 484           | 4    | 484           | 4    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysidxstats.clst      | 176           | 1    | 176           | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysidxstats.nc        | 144           | 1    | 144           | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysiscols.clst        | 100           | 1    | 100           | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysiscols.nc1         | 88            | 1    | 88            | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysobjvalues.clst     | 596           | 5    | 596           | 5    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysrowsets.clust      | 132           | 1    | 132           | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysrscols.clst        | 528           | 4    | 528           | 4    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysschobjs.clst       | 1040          | 6    | 1276          | 6    | 236              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysschobjs.nc1        | 820           | 6    | 1060          | 6    | 240              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysschobjs.nc2        | 820           | 6    | 1060          | 6    | 240              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysschobjs.nc3        | 480           | 6    | 480           | 6    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.syssingleobjrefs.clst | 96            | 1    |               |      | -96              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.syssingleobjrefs.nc1  | 88            | 1    |               |      | -88              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | Unknown Alloc Unit        | 72092         | 19   | 72092         | 19   |                  |
| LOP_DELETE_ROWS       | LCX_TEXT_MIX       | Unknown Alloc Unit        | 16348         | 37   | 16348         | 37   |                  |
| LOP_FORMAT_PAGE       | LCX_HEAP           | Unknown Alloc Unit        | 1596          | 19   | 1596          | 19   |                  |
| LOP_FORMAT_PAGE       | LCX_IAM            | Unknown Alloc Unit        | 252           | 3    | 252           | 3    |                  |
| LOP_FORMAT_PAGE       | LCX_INDEX_INTERIOR | Unknown Alloc Unit        | 84            | 1    | 84            | 1    |                  |
| LOP_FORMAT_PAGE       | LCX_TEXT_MIX       | Unknown Alloc Unit        | 4788          | 57   | 4788          | 57   |                  |
| LOP_HOBT_DDL          | LCX_NULL           |                           | 108           | 3    | 108           | 3    |                  |
| LOP_HOBT_DELTA        | LCX_NULL           |                           | 9600          | 150  | 9600          | 150  |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysallocunits.clust   | 456           | 3    | 456           | 3    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.syscolpars.clst       | 644           | 4    | 644           | 4    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysidxstats.clst      | 180           | 1    | 180           | 1    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysiscols.clst        | 104           | 1    | 104           | 1    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysobjvalues.clst     | 616           | 5    | 616           | 5    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysrowsets.clust      | 136           | 1    | 136           | 1    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysrscols.clst        | 544           | 4    | 544           | 4    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysschobjs.clst       | 1064          | 6    | 1300          | 6    | 236              |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.syssingleobjrefs.clst | 100           | 1    |               |      | -100             |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | Unknown Alloc Unit        | 135888        | 19   | 135888        | 19   |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_INTERIOR | Unknown Alloc Unit        | 1596          | 19   | 1596          | 19   |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysallocunits.nc      | 288           | 3    | 288           | 3    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.syscolpars.nc         | 500           | 4    | 500           | 4    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysidxstats.nc        | 148           | 1    | 148           | 1    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysiscols.nc1         | 92            | 1    | 92            | 1    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysschobjs.nc1        | 844           | 6    | 1084          | 6    | 240              |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysschobjs.nc2        | 844           | 6    | 1084          | 6    | 240              |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysschobjs.nc3        | 504           | 6    | 504           | 6    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.syssingleobjrefs.nc1  | 92            | 1    |               |      | -92              |
| LOP_INSERT_ROWS       | LCX_TEXT_MIX       | Unknown Alloc Unit        | 5112          | 71   | 5112          | 71   |                  |
| LOP_MARK_SAVEPOINT    | LCX_NULL           |                           | 508           | 8    | 508           | 8    |                  |
| LOP_MODIFY_COLUMNS    | LCX_CLUSTERED      | Unknown Alloc Unit        | 1560          | 10   | 1560          | 10   |                  |
| LOP_MODIFY_HEADER     | LCX_HEAP           | Unknown Alloc Unit        | 3780          | 45   | 3780          | 45   |                  |
| LOP_MODIFY_ROW        | LCX_CLUSTERED      | sys.syscolpars.clst       | 384           | 4    | 384           | 4    |                  |
| LOP_MODIFY_ROW        | LCX_CLUSTERED      | sys.sysidxstats.clst      | 100           | 1    | 100           | 1    |                  |
| LOP_MODIFY_ROW        | LCX_CLUSTERED      | sys.sysrowsets.clust      | 92            | 1    | 92            | 1    |                  |
| LOP_MODIFY_ROW        | LCX_CLUSTERED      | sys.sysschobjs.clst       | 1144          | 13   | 1144          | 13   |                  |
| LOP_MODIFY_ROW        | LCX_IAM            | Unknown Alloc Unit        | 4224          | 48   | 4224          | 48   |                  |
| LOP_MODIFY_ROW        | LCX_PFS            | Unknown Alloc Unit        | 13632         | 169  | 13632         | 169  |                  |
| LOP_MODIFY_ROW        | LCX_TEXT_MIX       | Unknown Alloc Unit        | 108640        | 120  | 108640        | 120  |                  |
| LOP_ROOT_CHANGE       | LCX_CLUSTERED      | sys.sysallocunits.clust   | 960           | 10   | 960           | 10   |                  |
| LOP_SET_BITS          | LCX_GAM            | Unknown Alloc Unit        | 1200          | 20   | 1200          | 20   |                  |
| LOP_SET_BITS          | LCX_IAM            | Unknown Alloc Unit        | 1080          | 18   | 1080          | 18   |                  |
| LOP_SET_BITS          | LCX_SGAM           | Unknown Alloc Unit        | 120           | 2    | 120           | 2    |                  |
| LOP_SHRINK_NOOP       | LCX_NULL           |                           |               |      | 32            | 1    | 32               |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
| Total                 |                    |                           | 410144        | 1095 | 411232        | 1092 | 1088             |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+

1
+1 Chỉ vì tò mò (và có một chút phạm vi). Câu hỏi là / đã khá cũ (tháng 8 năm 2008), vì vậy đó là về SQL 2005. Bây giờ chúng tôi đang ở năm 2011 (cuối năm) và SQL mới nhất là 2008 R2 cộng với bản beta Denali. Bạn đã sử dụng phiên bản nào?
xanatos

2
@xanatos - 2008. Vào năm 2005, các biến của bảng thực sự sẽ gặp bất lợi vì INSERT ... SELECTkhông được ghi nhật ký tối thiểu và bạn không thể SELECT INTO ... là biến bảng.
Martin Smith

1
Cảm ơn @MartinSmith, đã cập nhật câu trả lời của tôi để xóa yêu cầu về việc đăng nhập.
Rory

18

Trong những kịch bản nào người này thực hiện khác?

Đối với các bảng nhỏ hơn (dưới 1000 hàng), hãy sử dụng biến tạm thời, nếu không thì sử dụng bảng tạm thời.


17
Bất kỳ dữ liệu hỗ trợ? Điều này không hữu ích giống như một sự khẳng định của chính nó.
Michael Myers

8
Microsoft khuyến nghị giới hạn 100 hàng: msdn.microsoft.com/en-us/l Library / ms175010.aspx (xem phần Thực tiễn tốt nhất).
Artemix

Xem câu trả lời của tôi dưới đây để giải thích.
Quách Weihui

17

@wcm - thực ra để nit chọn Biến bảng không chỉ Ram - nó có thể được lưu trữ một phần trên đĩa.

Một bảng tạm thời có thể có các chỉ mục, trong khi một biến bảng chỉ có thể có một chỉ mục chính. Nếu tốc độ là một vấn đề Các biến của bảng có thể nhanh hơn, nhưng rõ ràng nếu có nhiều bản ghi hoặc nhu cầu tìm kiếm bảng tạm thời của một chỉ mục được nhóm, thì Bảng tạm thời sẽ tốt hơn.

Bài viết nền tốt


2
Bài viết nền tốt +1. Tôi sẽ xóa câu trả lời của mình kể từ khi sửa đổi nó sẽ không để lại nhiều và đã có rất nhiều câu trả lời hay
wcm

12
  1. Bảng Temp: Một bảng Temp dễ dàng tạo và sao lưu dữ liệu.

    Biến bảng: Nhưng biến bảng liên quan đến nỗ lực khi chúng ta thường tạo các bảng bình thường.

  2. Bảng tạm thời: Kết quả bảng tạm thời có thể được sử dụng bởi nhiều người dùng.

    Biến bảng: Nhưng chỉ có thể sử dụng biến bảng. 

  3. Bảng tạm thời: Bảng tạm thời sẽ được lưu trữ trong tempdb. Nó sẽ làm cho lưu lượng mạng. Khi chúng ta có dữ liệu lớn trong bảng tạm thời thì nó phải hoạt động trên cơ sở dữ liệu. Một vấn đề hiệu suất sẽ tồn tại.

    Biến bảng: Nhưng một biến bảng sẽ lưu trữ trong bộ nhớ vật lý cho một số dữ liệu, sau đó khi tăng kích thước, nó sẽ được chuyển sang tempdb.

  4. Bảng tạm thời: Bảng tạm thời có thể thực hiện tất cả các hoạt động DDL. Nó cho phép tạo các chỉ mục, thả, thay đổi, v.v.,

    Biến bảng: Trong khi đó biến bảng sẽ không cho phép thực hiện các thao tác DDL. Nhưng biến bảng chỉ cho phép chúng ta tạo chỉ mục cụm.

  5. Bảng tạm thời: Bảng tạm thời có thể được sử dụng cho phiên hiện tại hoặc toàn cầu. Vì vậy, một phiên nhiều người dùng có thể sử dụng các kết quả trong bảng.

    Biến bảng: Nhưng biến bảng có thể được sử dụng cho chương trình đó. (Thủ tục lưu trữ)

  6. Bảng Temp: Biến Temp không thể sử dụng các giao dịch. Khi chúng tôi thực hiện các hoạt động DML với bảng tạm thời thì nó có thể được khôi phục hoặc thực hiện các giao dịch.

    Biến bảng: Nhưng chúng ta không thể làm điều đó cho biến bảng.

  7. Bảng tạm thời: Các hàm không thể sử dụng biến tạm thời. Hơn nữa chúng ta không thể thực hiện thao tác DML trong các chức năng.

    Biến bảng: Nhưng hàm cho phép chúng ta sử dụng biến bảng. Nhưng sử dụng biến bảng chúng ta có thể làm điều đó.

  8. Bảng tạm thời: Quy trình được lưu trữ sẽ thực hiện việc biên dịch lại (không thể sử dụng cùng một kế hoạch thực hiện) khi chúng tôi sử dụng biến tạm thời cho mỗi cuộc gọi tiếp theo phụ.

    Biến bảng: Trong khi đó biến bảng sẽ không làm như vậy.


8

Đối với tất cả các bạn, những người tin rằng các biến tạm thời chỉ có trong bộ nhớ

Đầu tiên, biến bảng KHÔNG nhất thiết phải là bộ nhớ cư trú. Dưới áp lực bộ nhớ, các trang thuộc một biến bảng có thể được đẩy ra tempdb.

Đọc bài viết ở đây: TempDB :: Biến bảng so với bảng tạm thời cục bộ


3
Bạn có thể chỉnh sửa câu trả lời của bạn thành một câu trả lời duy nhất giải quyết hai điểm không?
Joshua Drake

7

Sự khác biệt chính khác là các biến bảng không có số liệu thống kê cột, như các bảng tạm thời làm. Điều này có nghĩa là trình tối ưu hóa truy vấn không biết có bao nhiêu hàng trong biến bảng (nó đoán 1), điều này có thể dẫn đến các kế hoạch không tối ưu cao được tạo ra nếu biến bảng thực sự có số lượng hàng lớn.


2
Các rowscột trong sys.partitionsđược duy trì cho các biến bảng để nó thực sự biết bao nhiêu hàng là trong bảng. Điều này có thể được nhìn thấy bằng cách sử dụng OPTION (RECOMPILE). Nhưng việc thiếu số liệu thống kê cột có nghĩa là nó không thể ước tính các vị từ cột cụ thể.
Martin Smith

7

Trích dẫn lấy từ; Chuyên gia và khắc phục sự cố SQL Server 2012

Thống kê Sự khác biệt chính giữa các bảng tạm thời và các biến bảng là số liệu thống kê không được tạo trên các biến bảng. Điều này có hai hậu quả lớn, trong đó đầu tiên là Trình tối ưu hóa truy vấn sử dụng ước tính cố định cho số lượng hàng trong một biến bảng bất kể dữ liệu chứa trong đó. Ngoài ra, việc thêm hoặc xóa dữ liệu không làm thay đổi dự toán.

Chỉ mục Bạn không thể tạo chỉ mục trên các biến của bảng mặc dù bạn có thể tạo các ràng buộc. Điều này có nghĩa là bằng cách tạo các khóa chính hoặc các ràng buộc duy nhất, bạn có thể có các chỉ mục (vì chúng được tạo để hỗ trợ các ràng buộc) trên các biến của bảng. Ngay cả khi bạn có các ràng buộc và do đó các chỉ mục sẽ có số liệu thống kê, các chỉ mục sẽ không được sử dụng khi truy vấn được biên dịch vì chúng sẽ không tồn tại vào thời gian biên dịch, chúng cũng không gây ra sự biên dịch lại.

Sửa đổi lược đồ Sửa đổi lược đồ có thể trên các bảng tạm thời nhưng không phải trên các biến bảng. Mặc dù các cation modifi lược đồ có thể có trên các bảng tạm thời, tránh sử dụng chúng vì chúng gây ra sự biên dịch lại các câu lệnh sử dụng các bảng.

Bảng tạm thời so với biến bảng

BẢNG BIỂU TƯỢNG KHÔNG ĐƯỢC TẠO TRONG NHỚ

Có một quan niệm sai lầm phổ biến rằng các biến bảng là cấu trúc trong bộ nhớ và do đó sẽ thực hiện nhanh hơn các bảng tạm thời . Nhờ một DMV được gọi là sys. dm _ db _ session _ space _ cách sử dụng, cho thấy việc sử dụng tempdb theo phiên, bạn có thể chứng minh rằng đó không phải là trường hợp . Sau khi khởi động lại SQL Server để xóa DMV, hãy chạy đoạn mã sau để xác nhận rằng phiên _ id của bạn trả về 0 cho người dùng _ đối tượng _ cấp phát _ trang _ đếm:

SELECT session_id,
database_id,
user_objects_alloc_page_count
FROM sys.dm_db_session_space_usage
WHERE session_id > 50 ;

Bây giờ bạn có thể kiểm tra một bảng tạm thời sử dụng bao nhiêu dung lượng bằng cách chạy tập lệnh sau để tạo một bảng tạm thời có một cột và điền vào một hàng:

CREATE TABLE #TempTable ( ID INT ) ;
INSERT INTO #TempTable ( ID )
VALUES ( 1 ) ;
GO
SELECT session_id,
database_id,
user_objects_alloc_page_count
FROM sys.dm_db_session_space_usage
WHERE session_id > 50 ;

Kết quả trên máy chủ của tôi chỉ ra rằng bảng được phân bổ một trang trong tempdb. Bây giờ chạy cùng một kịch bản nhưng sử dụng biến bảng lần này:

DECLARE @TempTable TABLE ( ID INT ) ;
INSERT INTO @TempTable ( ID )
VALUES ( 1 ) ;
GO
SELECT session_id,
database_id,
user_objects_alloc_page_count
FROM sys.dm_db_session_space_usage
WHERE session_id > 50 ;

Nên dùng cái nào?

Việc bạn có sử dụng các bảng tạm thời hoặc các biến bảng hay không nên được quyết định bằng cách kiểm tra kỹ lưỡng, nhưng tốt nhất nên nghiêng về các bảng tạm thời làm mặc định vì có rất ít điều có thể sai .

Tôi đã thấy khách hàng phát triển mã bằng cách sử dụng biến bảng vì họ đang xử lý một lượng nhỏ hàng và nó nhanh hơn bảng tạm thời, nhưng vài năm sau đó có hàng trăm nghìn hàng trong biến bảng và hiệu suất rất tệ , vì vậy hãy thử và cho phép lập kế hoạch năng lực khi bạn đưa ra quyết định!


Trong thực tế, số liệu thống kê được tạo trên các biến của bảng, xem stackoverflow.com/questions/42824366/NH
YuFeng Shen

4

Một điểm khác biệt:

Một var bảng chỉ có thể được truy cập từ các câu lệnh trong thủ tục tạo ra nó, không phải từ các thủ tục khác được gọi bởi thủ tục đó hoặc SQL động lồng nhau (thông qua exec hoặc sp_executesql).

Mặt khác, phạm vi của bảng tạm thời, bao gồm mã trong các thủ tục được gọi và SQL động lồng nhau.

Nếu bảng được tạo bởi thủ tục của bạn phải có thể truy cập được từ các thủ tục được gọi khác hoặc SQL động, bạn phải sử dụng bảng tạm thời. Điều này có thể rất tiện dụng trong các tình huống phức tạp.


2

Sự khác biệt giữa Temporary Tables (##temp/#temp)Table Variables (@table)là:

  1. Table variable (@table)được tạo ra trong memory. Trong khi đó, a Temporary table (##temp/#temp)được tạo ra trong tempdb database. Tuy nhiên, nếu có áp lực bộ nhớ, các trang thuộc về biến bảng có thể được đẩy sang tempdb.

  2. Table variableskhông thể tham gia vào transactions, logging or locking. Điều này làm cho @table faster then #temp. Vì vậy, biến bảng là nhanh hơn sau đó bảng tạm thời.

  3. Temporary tablecho phép sửa đổi Schema không giống như Table variables.

  4. Temporary tablescó thể nhìn thấy trong thói quen được tạo và cả trong thói quen con. Trong khi đó, các biến Bảng chỉ hiển thị trong thường trình được tạo.

  5. Temporary tablesđược phép CREATE INDEXestrong khi đó, Table variableskhông được phép CREATE INDEXthay vào đó họ có thể có chỉ mục bằng cách sử dụng Primary Key or Unique Constraint.


1

Cũng xem xét rằng bạn thường có thể thay thế cả hai bằng các bảng dẫn xuất cũng có thể nhanh hơn. Tuy nhiên, như với tất cả các điều chỉnh hiệu suất, chỉ các thử nghiệm thực tế đối với dữ liệu thực tế của bạn mới có thể cho bạn biết cách tiếp cận tốt nhất cho truy vấn cụ thể của bạn.


1

Điều làm tôi ngạc nhiên là không ai đề cập đến sự khác biệt chính giữa hai điều này là bảng tạm thời hỗ trợ chèn song song trong khi biến bảng không có. Bạn sẽ có thể thấy sự khác biệt từ kế hoạch thực hiện. Và đây là video từ Hội thảo SQL trên Kênh 9 .

Điều này cũng giải thích lý do tại sao bạn nên sử dụng biến tạm thời cho các bảng nhỏ hơn, nếu không thì sử dụng bảng tạm thời, như SQLMenace đã trả lời trước đó.

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.