Kapan saya harus menggunakan variabel tabel vs tabel sementara di sql server?


298

Saya belajar lebih detail dalam variabel tabel. Dikatakan bahwa tabel temp selalu di disk, dan variabel tabel ada di memori, artinya, kinerja variabel tabel lebih baik daripada tabel temp karena variabel tabel menggunakan lebih sedikit operasi IO daripada tabel temp.

Tetapi kadang-kadang, jika ada terlalu banyak catatan dalam variabel tabel yang tidak dapat terkandung dalam memori, variabel tabel akan diletakkan di disk seperti tabel temp.

Tapi saya tidak tahu apa "terlalu banyak catatan" itu. 100.000 catatan? atau 1000.000 catatan? Bagaimana saya bisa tahu jika variabel tabel yang saya gunakan ada di memori atau ada di disk? Apakah ada fungsi atau alat di SQL Server 2005 untuk mengukur skala variabel tabel atau memberi tahu saya ketika variabel tabel diletakkan di disk dari memori?


5
Variabel tabel hampir selalu di tempDB- bahwa "dalam memori" adalah mitos. Juga: variabel tabel akan selalu dianggap oleh pengoptimal kueri untuk memegang tepat satu baris - jika Anda memiliki lebih banyak baris, ini dapat menyebabkan rencana eksekusi yang sangat buruk.
marc_s


2
@marc_s - Anda dapat menjatuhkan "hampir" dalam pernyataan itu. Itu selalu dalam tempdb(tetapi mungkin juga sepenuhnya dalam memori)
Martin Smith

2
Dengan SQL 2014 Anda sekarang dapat membuat variabel tabel dalam memori
paparazzo

Jawaban:


362

Pertanyaan Anda menunjukkan 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 kedua jenis objek. Ini juga menjawab pertanyaan Anda tentang disk vs memori (saya tidak melihat perbedaan perilaku yang signifikan antara keduanya).

Mengenai pertanyaan dalam judul meskipun kapan menggunakan variabel tabel vs tabel sementara lokal Anda tidak selalu punya pilihan. Dalam fungsi, misalnya, hanya mungkin untuk menggunakan variabel tabel dan jika Anda perlu menulis ke tabel dalam lingkup anak maka hanya #temptabel yang akan melakukannya (parameter bernilai tabel memungkinkan akses hanya baca ).

Di mana Anda memiliki pilihan, beberapa saran ada di bawah ini (meskipun metode yang paling dapat diandalkan adalah dengan hanya menguji keduanya dengan beban kerja spesifik Anda).

  1. Jika Anda memerlukan indeks yang tidak dapat dibuat pada variabel tabel maka tentu saja Anda akan membutuhkan #temporarytabel. Namun rincian ini tergantung pada versi. Untuk SQL Server 2012 dan di bawah ini satu-satunya indeks yang dapat dibuat pada variabel tabel adalah mereka yang secara implisit dibuat melalui UNIQUEatau PRIMARY KEYkendala. SQL Server 2014 memperkenalkan sintaks indeks sebaris untuk subset dari opsi yang tersedia di CREATE INDEX. Ini telah diperpanjang sejak untuk memungkinkan kondisi indeks yang difilter. Indeks dengan INCLUDE-d kolom atau indeks kolomstore masih tidak memungkinkan untuk membuat variabel tabel.

  2. Jika Anda akan berulang kali menambahkan dan menghapus banyak baris dari tabel maka gunakan #temporarytabel. Itu mendukung TRUNCATE(yang lebih efisien daripada DELETEuntuk tabel besar) dan tambahan menyisipkan berikut TRUNCATEdapat memiliki kinerja yang lebih baik daripada yang mengikuti DELETE seperti yang diilustrasikan di sini .

  3. Jika Anda akan menghapus atau memperbarui sejumlah besar baris maka tabel temp mungkin berkinerja jauh lebih baik daripada variabel tabel - jika itu dapat menggunakan berbagi rowset (lihat "Efek berbagi rowset" di bawah untuk contoh).
  4. Jika rencana optimal menggunakan tabel akan bervariasi tergantung pada data kemudian gunakan #temporarytabel. Itu mendukung pembuatan statistik yang memungkinkan rencana untuk dikompilasi ulang secara dinamis sesuai dengan data (meskipun untuk tabel sementara cache dalam prosedur tersimpan , perilaku kompilasi perlu dipahami secara terpisah).
  5. Jika rencana optimal untuk kueri menggunakan tabel tidak mungkin pernah berubah maka Anda dapat mempertimbangkan variabel tabel untuk melewati overhead pembuatan statistik dan mengkompilasi ulang (mungkin akan memerlukan petunjuk untuk memperbaiki rencana yang Anda inginkan).
  6. Jika sumber untuk data yang dimasukkan ke tabel adalah dari SELECTpernyataan yang berpotensi mahal maka pertimbangkan bahwa menggunakan variabel tabel akan memblokir kemungkinan ini menggunakan rencana paralel.
  7. Jika Anda membutuhkan data dalam tabel untuk bertahan dari kemunduran transaksi pengguna luar maka gunakan variabel tabel. Kasus penggunaan yang mungkin untuk ini mungkin mencatat kemajuan langkah-langkah yang berbeda dalam batch SQL yang panjang.
  8. Ketika menggunakan #temptabel dalam transaksi pengguna kunci dapat ditahan lebih lama dari untuk variabel tabel (berpotensi sampai akhir transaksi vs akhir pernyataan tergantung pada jenis kunci dan tingkat isolasi) dan juga dapat mencegah pemotongan tempdblog transaksi hingga transaksi pengguna berakhir. Jadi ini mungkin mendukung penggunaan variabel tabel.
  9. Dalam rutinitas tersimpan, variabel tabel dan tabel sementara bisa di-cache. Pemeliharaan metadata untuk variabel tabel yang di-cache kurang dari itu untuk #temporarytabel. Bob Ward menunjukkan dalam tempdbpresentasinya bahwa ini dapat menyebabkan pertikaian tambahan pada tabel sistem dalam kondisi konkurensi tinggi. Selain itu, ketika berhadapan dengan sejumlah kecil data, ini dapat membuat perbedaan terukur untuk kinerja .

Efek berbagi rowset

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

2
Hai, Tuan Martin Smith. Dalam kasus mi saya hanya ingin menyimpan satu set nilai Id untuk menggunakannya dalam permintaan orang lain di dalam prosedur Store. Jadi apa yang Anda rekomendasikan kepada saya?
Jeancarlo Fontalvo

@JeancarloFontalvo - variabel tabel dengan kunci primer iddan penggunaan OPTION (RECOMPILE)mungkin akan baik untuk itu - tetapi uji keduanya.
Martin Smith

Apakah pertengkaran metadata sama untuk variabel tabel temp dan tabel?
Syed Aqeel Ashiq

@Syed. Biasanya lebih sedikit untuk TV. Kunci dapat dirilis lebih awal jika di dalam transaksi pengguna. Lihat juga tautan Bob Ward.
Martin Smith

73

Gunakan variabel tabel jika untuk jumlah data yang sangat kecil (ribuan byte)

Gunakan tabel sementara untuk banyak data

Cara lain untuk memikirkannya: jika Anda berpikir Anda mungkin mendapat manfaat dari indeks, statistik otomatis, atau kebaikan pengoptimal SQL, maka kumpulan data Anda mungkin terlalu besar untuk variabel tabel.

Dalam contoh saya, saya hanya ingin menempatkan sekitar 20 baris ke dalam format dan memodifikasinya sebagai grup, sebelum menggunakannya untuk MEMPERBARUI / MEMASANG tabel permanen. Jadi variabel tabel sempurna.

Tapi saya juga menjalankan SQL untuk mengisi kembali ribuan baris sekaligus, dan saya pasti bisa mengatakan bahwa tabel sementara berkinerja lebih baik daripada variabel tabel.

Ini tidak berbeda dengan bagaimana CTE menjadi perhatian karena alasan ukuran yang sama - jika data dalam CTE sangat kecil, saya menemukan CTE berkinerja sebaik atau lebih baik dari apa yang dihasilkan oleh pengoptimal, tetapi jika itu cukup besar maka itu menyakitkan kamu buruk.

Pemahaman saya sebagian besar didasarkan pada http://www.developerfusion.com/article/84397/table-variables-v-turnal-tables-in-sql-server/ , yang memiliki lebih banyak detail.


Takeaway adalah variabel tabel baik untuk dataset kecil, tetapi gunakan tabel temp untuk dataset lebih besar. Saya punya pertanyaan dengan ribuan baris. Dengan beralih dari variabel tabel ke tabel temp, waktu kueri turun dari 40 menjadi hanya 5 dengan semuanya dianggap sama.
liang

42

Microsoft mengatakan di sini

Variabel tabel tidak memiliki statistik distribusi, mereka tidak akan memicu kompilasi ulang. Oleh karena itu, dalam banyak kasus, pengoptimal akan membangun rencana kueri dengan asumsi bahwa variabel tabel tidak memiliki baris. Karena alasan ini, Anda harus berhati-hati dalam menggunakan variabel tabel jika Anda mengharapkan jumlah baris yang lebih besar (lebih besar dari 100). Tabel temp dapat menjadi solusi yang lebih baik dalam hal ini.


14

Saya sepenuhnya setuju dengan Abacus (maaf - tidak punya cukup poin untuk berkomentar).

Juga, perlu diingat bahwa itu tidak selalu turun ke berapa banyak catatan yang Anda miliki, tetapi ukuran catatan Anda.

Misalnya, apakah Anda mempertimbangkan perbedaan kinerja antara 1.000 catatan dengan 50 kolom masing-masing vs 100.000 catatan dengan hanya 5 kolom masing-masing?

Terakhir, mungkin Anda meminta / menyimpan lebih banyak data daripada yang Anda butuhkan? Berikut ini bacaan yang bagus tentang strategi optimasi SQL . Batasi jumlah data yang Anda tarik, terutama jika Anda tidak menggunakan semuanya (beberapa pemrogram SQL menjadi malas dan hanya memilih semuanya meskipun mereka hanya menggunakan sebagian kecil). Jangan lupa penganalisa query SQL juga bisa menjadi teman terbaik Anda.


4

Tabel variabel hanya tersedia untuk sesi saat ini, misalnya, jika Anda perlu EXECprosedur tersimpan lain dalam saat ini Anda harus melewati tabel karena Table Valued Parameterdan tentu saja ini akan mempengaruhi kinerja, dengan tabel sementara Anda dapat melakukan ini hanya dengan lewat nama tabel sementara

Untuk menguji tabel Sementara:

  • Buka editor kueri studio manajemen
  • Buat tabel sementara
  • Buka jendela editor kueri lain
  • Pilih dari tabel ini "Tersedia"

Untuk menguji tabel Variabel:

  • Buka editor kueri studio manajemen
  • Buat tabel Variabel
  • Buka jendela editor kueri lain
  • Pilih dari tabel ini "Tidak Tersedia"

sesuatu yang lain yang saya alami adalah: Jika skema Anda tidak memiliki GRANThak istimewa untuk membuat tabel maka gunakan tabel variabel.


3

menulis data dalam tabel yang dideklarasikan declare @tbdan setelah bergabung dengan tabel lain, saya menyadari bahwa waktu respons dibandingkan dengan tabel sementara tempdb .. # tbjauh lebih tinggi.

Ketika saya bergabung dengan mereka dengan @tb , waktu jauh lebih lama untuk mengembalikan hasilnya, tidak seperti #tm , pengembaliannya hampir seketika.

Saya melakukan tes dengan 10.000 baris bergabung dan bergabung dengan 5 tabel lainnya


Bisakah Anda memposting tes Anda berlari untuk mendapatkan angka-angka ini?
Dan Def
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.