Sorunuz, tablo değişkenlerini ve geçici tabloları çevreleyen bazı yaygın yanılgılara yenildiğinizi gösteriyor.
İki nesne türü arasındaki farklara bakarak DBA sitesinde oldukça kapsamlı bir cevap yazdım . Bu aynı zamanda disk vs bellek hakkında sorunuzu ele alıyor (ikisi arasında davranışta önemli bir fark görmedim).
Başlıktaki soru ile ilgili olarak, bir tablo değişkeninin yerel bir geçici tabloya karşı ne zaman kullanılacağı konusunda her zaman bir seçeneğiniz yoktur. Örneğin işlevlerde, bir tablo değişkeni kullanmak mümkündür ve tabloya bir alt kapsamda yazmanız gerekirse, yalnızca bir #temp
tablo yapılır (tablo değerli parametreler salt okunur erişime izin verir ).
Bir seçeneğiniz olduğunda, bazı öneriler aşağıdadır (en güvenilir yöntem her ikisini de belirli iş yükünüzle test etmektir).
Bir tablo değişkeninde oluşturulamayan bir dizine ihtiyacınız varsa, elbette bir #temporary
tabloya ihtiyacınız olacaktır . Ancak bunun ayrıntıları sürüme bağlıdır. SQL Server 2012 ve altı için yalnızca tablo değişkenleri üzerinde oluşturulabilecek dizinler dolaylı olarak bir UNIQUE
veya PRIMARY KEY
kısıtlamasıyla oluşturulmuş dizinlerdir . SQL Server 2014, mevcut seçeneklerin bir alt kümesi için satır içi dizin sözdizimini tanıttı CREATE INDEX
. Bu, filtrelenmiş dizin koşullarına izin verdiği için genişletildi. INCLUDE
Bununla birlikte , -d sütunları veya sütun deposu dizinleri içeren dizinler hala tablo değişkenlerinde oluşturulamaz.
Tabloya tekrar tekrar çok sayıda satır ekleyip silecekseniz bir #temporary
tablo kullanın . Bu destekler TRUNCATE
( DELETE
büyük tablolardan daha etkilidir ) ve a'yı takip eden ek kesici uçlar , burada gösterilen a'yıTRUNCATE
izleyenlerden daha iyi performans DELETE
gösterebilir .
- Çok sayıda satırı silecekseniz veya güncelleyecekseniz, geçici tablo bir tablo değişkeninden çok daha iyi performans gösterebilir - satır kümesi paylaşımını kullanabiliyorsa (örnek için aşağıdaki "Satır kümesi paylaşımının etkileri" konusuna bakın).
- Tabloyu kullanarak en uygun plan verilere bağlı olarak değişecekse, tablo kullanın
#temporary
. Bu, planın verilere göre dinamik olarak yeniden derlenmesini sağlayan istatistiklerin oluşturulmasını destekler (saklı yordamlardaki önbelleğe alınmış geçici tablolar için yeniden derleme davranışının ayrı olarak anlaşılması gerekir).
- Tabloyu kullanarak sorgu için en uygun planın değişmesi olası değilse, istatistik oluşturma ve yeniden derleme yükünü atlamak için bir tablo değişkenini düşünebilirsiniz (muhtemelen istediğiniz planı düzeltmek için ipuçları gerekebilir).
- Tabloya eklenen verilerin kaynağı potansiyel olarak pahalı bir
SELECT
ifadeden geliyorsa, bir tablo değişkeni kullanmanın bunun paralel bir plan kullanarak bunun olasılığını engelleyeceğini düşünün.
- Bir dış kullanıcı işleminin geri alınması için tablodaki verilere ihtiyacınız varsa bir tablo değişkeni kullanın. Bunun olası bir kullanım durumu, uzun adımların ilerlemesini uzun bir SQL toplu işleminde günlüğe kaydetme olabilir.
- Bir
#temp
kullanıcı içinde bir tablo kullanıldığında, işlem kilitleri tablo değişkenlerinden daha uzun süre tutulabilir (işlemin sonuna kadar, ifadenin sonuna kadar kilit türüne ve yalıtım düzeyine bağlı olarak) ve ayrıca tempdb
işlem günlüğünün kesilmesini önleyebilir kullanıcı işlemi sona erer. Yani bu tablo değişkenlerinin kullanılmasını destekleyebilir.
- Depolanan rutinler içinde hem tablo değişkenleri hem de geçici tablolar önbelleğe alınabilir. Önbelleğe alınan tablo değişkenleri için meta veri bakımı
#temporary
tablolardan daha azdır . Bob Ward tempdb
sunumunda bunun yüksek eşzamanlılık koşullarında sistem tablolarında ek tartışmaya neden olabileceğine dikkat çekiyor . Ek olarak, az miktarda veriyle uğraşırken, bu durum performansta ölçülebilir bir fark yaratabilir .
Satır kümesi paylaşımının etkileri
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
- "bellekte" bir efsanedir. Ayrıca: tablo değişkenleri her zaman sorgu iyileştirici tarafından tam olarak bir satır tutacaktır - çok daha fazlasına sahipseniz, bu durum çok kötü yürütme planlarına yol açabilir.