Apa perbedaan antara variabel tabel temp dan tabel dalam SQL Server?

390

Di SQL Server 2005, kita bisa membuat tabel temp salah satu dari dua cara:

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

atau

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

Apa perbedaan antara keduanya? Saya telah membaca pendapat yang bertentangan tentang apakah @tmp masih menggunakan tempdb, atau jika semuanya terjadi dalam memori.

Dalam skenario mana salah satu melakukan yang lainnya?

Eric Z Beard
sumber
2
Ada tulisan yang sangat bagus dari Pinal Dave di sini ... blog.sqlauthority.com/2009/12/15/…
sam yi

Jawaban:

392

Ada beberapa perbedaan antara Tabel Sementara (#tmp) dan Tabel Variabel (@tmp), meskipun menggunakan tempdb bukan salah satunya, sebagaimana dijabarkan dalam tautan MSDN di bawah ini.

Sebagai pedoman praktis, untuk volume data kecil dan menengah dan skenario penggunaan sederhana, Anda harus menggunakan variabel tabel. (Ini adalah pedoman yang terlalu luas dengan tentu saja banyak pengecualian - lihat di bawah dan artikel berikut.)

Beberapa hal yang perlu dipertimbangkan ketika memilih di antara mereka:

  • Tabel Sementara adalah tabel nyata sehingga Anda dapat melakukan hal-hal seperti BUAT INDEKS, dll. Jika Anda memiliki sejumlah besar data yang mengakses dengan indeks lebih cepat maka tabel sementara adalah pilihan yang baik.

  • Variabel tabel dapat memiliki indeks dengan menggunakan kendala PRIMARY KEY atau UNIK. (Jika Anda ingin indeks non-unik cukup sertakan kolom kunci utama sebagai kolom terakhir dalam batasan unik. Jika Anda tidak memiliki kolom unik, Anda dapat menggunakan kolom identitas.) SQL 2014 juga memiliki indeks tidak unik .

  • Variabel tabel tidak berpartisipasi dalam transaksi dan SELECTsecara implisit dengan NOLOCK. Perilaku transaksi bisa sangat membantu, misalnya jika Anda ingin ROLLBACK di tengah prosedur maka variabel tabel yang diisi selama transaksi itu masih akan diisi!

  • Tabel temp dapat menghasilkan prosedur tersimpan yang dikompilasi ulang, mungkin sering. Variabel tabel tidak akan.

  • Anda bisa membuat tabel temp menggunakan SELECT INTO, yang bisa lebih cepat untuk menulis (baik untuk permintaan ad-hoc) dan memungkinkan Anda untuk berurusan dengan mengubah tipe data dari waktu ke waktu, karena Anda tidak perlu menentukan struktur tabel temp Anda di muka.

  • Anda bisa meneruskan variabel tabel kembali dari fungsi, memungkinkan Anda untuk merangkum dan menggunakan kembali logika jauh lebih mudah (misalnya membuat fungsi untuk membagi string menjadi tabel nilai pada beberapa pembatas yang berubah-ubah).

  • Menggunakan Tabel Variabel dalam fungsi-fungsi yang ditentukan pengguna memungkinkan fungsi-fungsi itu digunakan lebih luas (lihat CREATE FUNCTION dokumentasi untuk detailnya). Jika Anda menulis fungsi, Anda harus menggunakan variabel tabel di atas tabel temp kecuali jika ada kebutuhan yang mendesak.

  • Variabel tabel dan tabel temp disimpan dalam tempdb. Tetapi variabel tabel (sejak 2005) default untuk collation dari database saat ini versus temp tables yang mengambil collation default tempdb ( ref ). Ini berarti Anda harus mengetahui masalah pengumpulan jika menggunakan tabel temp dan pengumpulan db Anda berbeda dengan tempdb, yang menyebabkan masalah jika Anda ingin membandingkan data di tabel temp dengan data di database Anda.

  • Global Temp Tables (## tmp) adalah jenis tabel temp lainnya yang tersedia untuk semua sesi dan pengguna.

Beberapa bacaan lebih lanjut:

Rory
sumber
26
Variabel tabel dapat memiliki indeks. Cukup buat kendala unik, dan Anda secara otomatis mendapatkan indeks. Membuat perbedaan kinerja yang sangat besar. (Jika Anda tidak menginginkan indeks unik, cukup tambahkan kunci utama yang sebenarnya di akhir bidang yang Anda inginkan. Jika Anda belum memilikinya, buat kolom identitas).
Ben
7
@ Ben dan SQL Server 2014 memungkinkan indeks tidak unik untuk ditentukan pada variabel tabel
Martin Smith
4
Variabel tabel yang tidak terpengaruh oleh transaksi terkadang berguna. Jika Anda memiliki sesuatu yang ingin Anda simpan setelah rollback, Anda bisa memasukkannya ke dalam variabel tabel.
quillbreaker
3
Statistik dibuat untuk tabel temp, yang dapat membuat rencana kueri lebih baik, tetapi tidak untuk variabel tabel. Statistik ini di-cache untuk sementara waktu, bersama dengan halaman tabel temp, setelah tabel temp dihapus dan mungkin tidak akurat jika tabel di-cache diaktifkan kembali.
Michael Green
Variabel-variabel tabel akan default ke collation dari tipe data yang ditentukan pengguna (jika kolom adalah tipe data yang ditentukan pengguna) atau collation dari database saat ini dan bukan collation default tempdb. Tabel temp akan menggunakan susunan default tempdb. Lihat: technet.microsoft.com/en-us/library/ms188927.aspx
PseudoToad
25

Hanya dengan melihat klaim dalam jawaban yang diterima bahwa variabel tabel tidak berpartisipasi dalam pencatatan.

Secara umum tampaknya tidak benar bahwa ada perbedaan dalam jumlah penebangan (setidaknya untuk insert/ update/ deleteoperasi ke tabel itu sendiri meskipun saya sejak itu menemukan bahwa ada beberapa perbedaan kecil dalam hal ini untuk objek sementara di-cache dalam prosedur tersimpan karena tabel sistem tambahan pembaruan).

Saya melihat perilaku logging terhadap a @table_variabledan #temptabel untuk operasi berikut.

  1. Masukkan berhasil
  2. Sisipan Multi Baris tempat pernyataan dibatalkan karena pelanggaran batasan.
  3. Memperbarui
  4. Menghapus
  5. Deallocate

Catatan log transaksi hampir identik untuk semua operasi.

Versi variabel tabel sebenarnya memiliki beberapa entri log tambahan karena mendapat entri yang ditambahkan ke (dan kemudian dihapus dari) sys.syssingleobjrefstabel dasar tetapi secara keseluruhan memiliki beberapa byte kurang dicatat murni sebagai nama internal untuk variabel tabel mengkonsumsi 236 byte lebih sedikit daripada untuk #temptabel (118 nvarcharkarakter lebih sedikit ).

Skrip lengkap untuk direproduksi (dijalankan terbaik pada contoh yang dimulai dalam mode pengguna tunggal dan menggunakan sqlcmdmode)

: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),())

Hasil

+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
|                       |                    |                           |             @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             |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
Martin Smith
sumber
1
+1 Hanya karena penasaran (dan menjadi sedikit bertele-tele). Pertanyaannya adalah / sudah cukup lama (Agustus 2008), jadi itu tentang SQL 2005. Sekarang kita berada di 2011 (akhir) dan SQL terbaru adalah 2008 R2 ditambah beta Denali. Versi apa yang Anda gunakan?
xanatos
2
@xanatos - 2008. Pada 2005 tabel variabel sebenarnya akan dirugikan karena INSERT ... SELECTtidak dicatat minimal dan Anda tidak bisa SELECT INTO ... variabel tabel.
Martin Smith
1
Terima kasih @MartinSmith, memperbarui jawaban saya untuk menghapus klaim tentang pencatatan.
Rory
18

Dalam skenario mana salah satu melakukan yang lainnya?

Untuk tabel yang lebih kecil (kurang dari 1000 baris) gunakan variabel temp, jika tidak gunakan tabel temp.

SQLMenace
sumber
17
Adakah data pendukung? Ini tidak terlalu membantu hanya sebagai pernyataan sendiri.
Michael Myers
8
Microsoft merekomendasikan batas 100 baris: msdn.microsoft.com/en-us/library/ms175010.aspx (lihat bagian Praktik Terbaik).
Artemix
Lihat jawaban saya di bawah untuk penjelasan.
Weihui Guo
17

@ wcm - sebenarnya untuk nit memilih Table Variable bukan hanya Ram - itu dapat disimpan sebagian pada disk.

Tabel temp dapat memiliki indeks, sedangkan variabel tabel hanya dapat memiliki indeks primer. Jika kecepatan masalah Tabel variabel bisa lebih cepat, tetapi jelas jika ada banyak catatan, atau kebutuhan untuk mencari tabel temp indeks berkerumun, maka Tabel Temp akan lebih baik.

Artikel latar belakang yang bagus

James Sugrue
sumber
2
Artikel latar belakang yang bagus +1. Saya akan menghapus jawaban saya karena mengubahnya tidak akan meninggalkan banyak dan sudah ada begitu banyak jawaban bagus
wcm
12
  1. Temp table: Temp table mudah untuk membuat dan membuat cadangan data.

    Variabel tabel: Tapi variabel tabel melibatkan upaya ketika kita biasanya membuat tabel normal.

  2. Tabel temp: Hasil tabel temp dapat digunakan oleh banyak pengguna.

    Variabel tabel: Tetapi variabel tabel hanya dapat digunakan oleh pengguna saat ini. 

  3. Temp table: Temp table akan disimpan di tempdb. Ini akan membuat lalu lintas jaringan. Ketika kita memiliki data besar di tabel temp maka itu harus bekerja di database. Masalah kinerja akan ada.

    Variabel tabel: Tetapi variabel tabel akan menyimpan dalam memori fisik untuk beberapa data, kemudian nanti ketika ukurannya meningkat, akan dipindahkan ke tempdb.

  4. Temp table: Temp table dapat melakukan semua operasi DDL. Memungkinkan membuat indeks, menjatuhkan, mengubah, dll.,

    Variabel tabel: Sedangkan variabel tabel tidak akan memungkinkan melakukan operasi DDL. Tetapi variabel tabel memungkinkan kita untuk membuat hanya indeks berkerumun.

  5. Temp table: Temp table dapat digunakan untuk sesi saat ini atau global. Sehingga sesi beberapa pengguna dapat memanfaatkan hasil dalam tabel.

    Variabel tabel: Tetapi variabel tabel dapat digunakan hingga program itu. (Prosedur tersimpan)

  6. Tabel temp: Variabel temp tidak dapat menggunakan transaksi. Ketika kita melakukan operasi DML dengan tabel temp maka itu bisa rollback atau melakukan transaksi.

    Variabel tabel: Tapi kita tidak bisa melakukannya untuk variabel tabel.

  7. Tabel temp: Fungsi tidak dapat menggunakan variabel temp. Terlebih lagi kita tidak bisa melakukan operasi DML dalam fungsi.

    Variabel tabel: Tetapi fungsi memungkinkan kita untuk menggunakan variabel tabel. Tetapi menggunakan variabel tabel kita bisa melakukan itu.

  8. Tabel temp: Prosedur tersimpan akan melakukan kompilasi ulang (tidak dapat menggunakan rencana eksekusi yang sama) saat kami menggunakan variabel temp untuk setiap panggilan sub sekuensial.

    Variabel tabel: Sedangkan variabel tabel tidak akan melakukan seperti itu.

Kumar Manish
sumber
8

Untuk Anda semua yang percaya mitos bahwa variabel temp hanya dalam memori

Pertama, variabel tabel TIDAK harus residen memori. Di bawah tekanan memori, halaman milik variabel tabel dapat didorong keluar ke tempdb.

Baca artikel di sini: TempDB :: Tabel variabel vs tabel sementara lokal

SQLMenace
sumber
3
Bisakah Anda mengedit jawaban Anda menjadi satu jawaban yang membahas dua poin?
Joshua Drake
7

Perbedaan utama lainnya adalah variabel tabel tidak memiliki statistik kolom, seperti halnya tabel temp. Ini berarti bahwa optimizer kueri tidak tahu berapa banyak baris dalam variabel tabel (tebakan 1), yang dapat menyebabkan rencana yang sangat tidak optimal dihasilkan jika variabel tabel sebenarnya memiliki sejumlah besar baris.

GilaMonster
sumber
2
The rowskolom sys.partitionsdipertahankan untuk variabel meja sehingga tidak benar-benar tahu berapa banyak baris dalam tabel. Ini bisa dilihat dengan menggunakan OPTION (RECOMPILE). Tetapi kurangnya statistik kolom berarti tidak dapat memperkirakan predikat kolom tertentu.
Martin Smith
7

Kutipan diambil dari; Profesional SQL Server 2012 Internal dan Pemecahan Masalah

Statistik Perbedaan utama antara tabel temp dan variabel tabel adalah bahwa statistik tidak dibuat pada variabel tabel. Ini memiliki dua konsekuensi utama, yang pertama adalah bahwa Query Optimizer menggunakan estimasi tetap untuk jumlah baris dalam variabel tabel terlepas dari data yang dikandungnya. Selain itu, menambah atau menghapus data tidak mengubah estimasi.

Indeks Anda tidak dapat membuat indeks pada variabel tabel meskipun Anda dapat membuat batasan. Ini berarti bahwa dengan membuat kunci utama atau batasan unik, Anda dapat memiliki indeks (karena ini dibuat untuk mendukung kendala) pada variabel tabel. Bahkan jika Anda memiliki kendala, dan karena itu indeks yang akan memiliki statistik, indeks tidak akan digunakan ketika permintaan dikompilasi karena mereka tidak akan ada pada waktu kompilasi, juga tidak akan menyebabkan kompilasi ulang.

Modifikasi Skema Modifikasi skema dimungkinkan pada tabel sementara tetapi tidak pada variabel tabel. Meskipun modifikasi skema dimungkinkan pada tabel sementara, hindari menggunakannya karena mereka menyebabkan kompilasi ulang pernyataan yang menggunakan tabel.

Tabel Sementara versus Variabel Tabel

VARIABEL TABEL TIDAK DICIPTAKAN DALAM MEMORI

Ada kesalahpahaman umum bahwa variabel tabel adalah struktur di-memori dan dengan demikian akan melakukan lebih cepat daripada tabel sementara . Berkat DMV yang disebut sys. dm _ db _ session _ spasi _ penggunaan, yang menunjukkan penggunaan tempdb per sesi, Anda dapat membuktikan bahwa bukan itu masalahnya . Setelah memulai ulang SQL Server untuk menghapus DMV, jalankan skrip berikut untuk mengonfirmasi bahwa sesi Anda _ id mengembalikan 0 untuk pengguna _ objek _ mengalokasikan _ halaman _ menghitung:

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

Sekarang Anda dapat memeriksa berapa banyak ruang yang digunakan tabel sementara dengan menjalankan skrip berikut untuk membuat tabel sementara dengan satu kolom dan mengisinya dengan satu baris:

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 ;

Hasil di server saya menunjukkan bahwa tabel dialokasikan satu halaman di tempdb. Sekarang jalankan skrip yang sama tetapi gunakan variabel tabel kali ini:

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 ;

Yang mana yang akan digunakan?

Apakah Anda menggunakan tabel sementara atau variabel tabel harus diputuskan dengan pengujian menyeluruh, tetapi yang terbaik adalah condong ke tabel sementara sebagai default karena ada jauh lebih sedikit hal yang bisa salah .

Saya telah melihat pelanggan mengembangkan kode menggunakan variabel tabel karena mereka berhadapan dengan sejumlah kecil baris, dan itu lebih cepat daripada tabel sementara, tetapi beberapa tahun kemudian ada ratusan ribu baris dalam variabel tabel dan kinerja sangat buruk. , jadi cobalah dan izinkan perencanaan kapasitas ketika Anda membuat keputusan!

Teoman shipahi
sumber
Faktanya, statistik dibuat pada variabel tabel, lihat stackoverflow.com/questions/42824366/…
YuFeng Shen
4

Perbedaan lain:

Tabel var hanya dapat diakses dari pernyataan di dalam prosedur yang membuatnya, bukan dari prosedur lain yang dipanggil oleh prosedur itu atau bersarang SQL dinamis (via exec atau sp_executesql).

Ruang lingkup tabel temp, di sisi lain, termasuk kode dalam prosedur yang disebut dan SQL dinamis bersarang.

Jika tabel yang dibuat oleh prosedur Anda harus dapat diakses dari prosedur lain yang disebut atau SQL dinamis, Anda harus menggunakan tabel temp. Ini bisa sangat berguna dalam situasi yang kompleks.

BrianFinkel
sumber
2

Perbedaan antara Temporary Tables (##temp/#temp)dan Table Variables (@table)adalah sebagai:

  1. Table variable (@table)dibuat di memory. Sedangkan, Temporary table (##temp/#temp)dibuat di tempdb database. Namun, jika ada tekanan memori halaman-halaman yang termasuk variabel tabel dapat didorong ke tempdb.

  2. Table variablestidak dapat terlibat dalam transactions, logging or locking. Ini membuat @table faster then #temp. Jadi variabel tabel lebih cepat daripada tabel sementara.

  3. Temporary tablememungkinkan modifikasi Skema tidak seperti Table variables.

  4. Temporary tablesterlihat dalam rutinitas yang dibuat dan juga dalam rutinitas anak. Sedangkan, variabel Tabel hanya terlihat dalam rutin yang dibuat.

  5. Temporary tablesdiizinkan CREATE INDEXessedangkan, Table variablestidak diizinkan CREATE INDEXsebaliknya mereka dapat memiliki indeks dengan menggunakan Primary Key or Unique Constraint.

Litisqe Kumar
sumber
1

Pertimbangkan juga bahwa Anda sering dapat mengganti keduanya dengan tabel turunan yang mungkin lebih cepat juga. Seperti semua penyetelan kinerja, hanya tes yang sebenarnya terhadap data aktual Anda yang dapat memberi tahu Anda pendekatan terbaik untuk permintaan khusus Anda.

HLGEM
sumber
1

Itu mengejutkan saya bahwa tidak ada yang menyebutkan perbedaan utama antara keduanya adalah bahwa tabel temp mendukung dukungan paralel sementara variabel tabel tidak. Anda harus dapat melihat perbedaan dari rencana eksekusi. Dan inilah video dari SQL Workshops di Channel 9 .

Ini juga menjelaskan mengapa Anda harus menggunakan variabel temp untuk tabel yang lebih kecil, jika tidak gunakan tabel temp, seperti yang dijawab SQLMenace sebelumnya.

Weihui Guo
sumber