Pertanyaan Anda menunjukkan bahwa Anda telah menyerah pada beberapa kesalahpahaman umum seputar variabel tabel dan tabel sementara.
Saya telah menulis jawaban yang cukup luas di situs DBA melihat perbedaan antara dua jenis objek. Ini juga menjawab pertanyaan Anda tentang disk vs memori (saya tidak melihat perbedaan perilaku yang signifikan di antara keduanya).
Mengenai pertanyaan dalam judul tentang kapan harus menggunakan variabel tabel vs tabel sementara lokal, Anda tidak selalu punya pilihan. Dalam fungsi, misalnya, hanya mungkin menggunakan variabel tabel dan jika Anda perlu menulis ke tabel dalam lingkup anak maka hanya #temp
tabel akan melakukannya (parameter bernilai tabel memungkinkan akses hanya baca).
Jika Anda memiliki pilihan, beberapa saran ada di bawah (meskipun metode yang paling dapat diandalkan adalah dengan menguji keduanya dengan beban kerja spesifik Anda).
-
Jika Anda memerlukan indeks yang tidak dapat dibuat pada variabel tabel maka Anda tentu memerlukan
#temporary
meja. Namun, detailnya bergantung pada versi. Untuk SQL Server 2012 dan di bawahnya, satu-satunya indeks yang dapat dibuat pada variabel tabel adalah yang dibuat secara implisit melaluiUNIQUE
atauPRIMARY KEY
paksaan. SQL Server 2014 memperkenalkan sintaks indeks sebaris untuk subset opsi yang tersedia diCREATE INDEX
. Ini telah diperpanjang sejak untuk memungkinkan kondisi indeks yang difilter. Indeks denganINCLUDE
-d kolom atau indeks columnstore masih tidak mungkin dibuat pada variabel tabel. -
Jika Anda akan berulang kali menambahkan dan menghapus sejumlah besar baris dari tabel, gunakan
#temporary
meja. Itu mendukungTRUNCATE
(yang lebih efisien daripadaDELETE
untuk tabel besar) dan tambahan penyisipan berikutnya mengikutiTRUNCATE
dapat memiliki kinerja yang lebih baik daripada yang mengikutiDELETE
seperti yang diilustrasikan di sini. - Jika Anda akan menghapus atau memperbarui sejumlah besar baris maka tabel temp mungkin berkinerja jauh lebih baik daripada variabel tabel - jika dapat menggunakan berbagi baris (lihat "Efek berbagi baris" di bawah untuk contoh) .
- Jika rencana optimal menggunakan tabel akan bervariasi tergantung pada data maka gunakan
#temporary
meja. Itu mendukung pembuatan statistik yang memungkinkan rencana untuk dikompilasi ulang secara dinamis sesuai dengan data (meskipun untuk tabel sementara yang di-cache dalam prosedur tersimpan, perilaku kompilasi ulang perlu dipahami secara terpisah). - Jika rencana optimal untuk kueri menggunakan tabel kemungkinan tidak akan pernah berubah, Anda dapat mempertimbangkan variabel tabel untuk melewati overhead pembuatan statistik dan kompilasi ulang (mungkin memerlukan petunjuk untuk memperbaiki rencana yang Anda inginkan).
- Jika sumber data yang dimasukkan ke tabel berasal dari
SELECT
. yang berpotensi mahal pernyataan kemudian pertimbangkan bahwa menggunakan variabel tabel akan memblokir kemungkinan ini menggunakan rencana paralel. - Jika Anda memerlukan data dalam tabel untuk bertahan dari rollback transaksi pengguna luar, gunakan variabel tabel. Kemungkinan kasus penggunaan untuk ini mungkin mencatat kemajuan langkah-langkah yang berbeda dalam kumpulan SQL yang panjang.
- Saat menggunakan
#temp
tabel dalam kunci transaksi pengguna dapat disimpan lebih lama daripada variabel tabel (berpotensi hingga akhir transaksi vs akhir pernyataan tergantung pada jenis kunci dan tingkat isolasi) dan juga dapat mencegah pemotongantempdb
log transaksi sampai transaksi pengguna berakhir. Jadi ini mungkin mendukung penggunaan variabel tabel. - Dalam rutinitas yang tersimpan, variabel tabel dan tabel sementara dapat di-cache. Pemeliharaan metadata untuk variabel tabel yang di-cache kurang dari itu untuk
#temporary
tabel. Bob Ward menunjukkan dalamtempdb
-nya presentasi bahwa ini dapat menyebabkan pertentangan tambahan pada tabel sistem dalam kondisi konkurensi tinggi. Selain itu, saat menangani data dalam jumlah kecil, hal ini dapat membuat perbedaan kinerja yang terukur.
Efek berbagi baris baris
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