SQL Server'da geçici tablo ve tablo değişkeni arasındaki fark nedir?


390

SQL Server 2005'te geçici tabloları iki yoldan biriyle oluşturabiliriz:

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

veya

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

Bu ikisi arasındaki farklar nelerdir? @Tmp'nin hala tempdb kullanıp kullanmadığı veya her şeyin bellekte olup olmadığı hakkında çelişkili görüşler okudum.

Biri hangi senaryolarda diğerini gerçekleştiriyor?



2
Burada Pinal Dave tarafından gerçekten iyi bir yazı var ... blog.sqlauthority.com/2009/12/15/…
sam yi

Yanıtlar:


392

Geçici Tablolar (#tmp) ve Tablo Değişkenleri (@tmp) arasında birkaç fark vardır, ancak tempdb kullanımı aşağıdaki MSDN bağlantısında belirtildiği gibi bunlardan biri değildir.

Genel bir kural olarak, küçük ve orta hacimli veri ve basit kullanım senaryoları için tablo değişkenlerini kullanmalısınız. (Bu, elbette birçok istisna dışında aşırı geniş bir kılavuzdur - aşağıya ve aşağıdaki makalelere bakın.)

Aralarında seçim yaparken dikkate alınması gereken bazı noktalar:

  • Geçici Tablolar CREATE INDEXes, vb. Gibi şeyler yapabilmeniz için gerçek tablolardır. Eğer indekse erişimin daha hızlı olacağı büyük miktarda veri varsa, geçici tablolar iyi bir seçenektir.

  • Tablo değişkenleri, PRIMARY KEY veya UNIQUE kısıtlamaları kullanılarak dizinlere sahip olabilir. (Benzersiz olmayan bir dizin istiyorsanız, benzersiz kısıtlamadaki son sütun olarak birincil anahtar sütununu ekleyin. Benzersiz bir sütununuz yoksa, bir kimlik sütunu kullanabilirsiniz.) SQL 2014'ün benzersiz olmayan dizinleri de vardır .

  • Tablo değişkenleri işlemlere katılmaz ve SELECTdolaylı olarak NOLOCK. İşlem davranışı çok yararlı olabilir, örneğin bir yordamın ortasında GERİ DÖNMEK istiyorsanız, bu işlem sırasında doldurulan tablo değişkenleri yine de doldurulur!

  • Geçici tablolar, saklı yordamların yeniden derlenmesine neden olabilir. Tablo değişkenleri değişmez.

  • SELECT INTO kullanarak yazmak için daha hızlı (geçici sorgulama için iyi) bir geçici tablo oluşturabilir ve geçici tablo yapınızı önceden tanımlamanız gerekmediğinden zaman içinde değişen veri türleriyle uğraşmanıza izin verebilir.

  • Tablo değişkenlerini işlevlerden geri aktarabilirsiniz, böylece mantığı çok daha kolay bir şekilde kapsülleyebilir ve yeniden kullanabilirsiniz (örneğin, bir dizeyi bazı rastgele sınırlayıcılarda bir değer tablosuna bölmek için bir işlev yapın).

  • Kullanıcı tarafından tanımlanan işlevlerde Tablo Değişkenlerinin kullanılması, bu işlevlerin daha yaygın olarak kullanılmasını sağlar (ayrıntılar için İŞLEV OLUŞTURMA belgelerine bakın). Bir işlev yazıyorsanız, zorlayıcı bir gereksinim olmadıkça geçici tablolar üzerinde tablo değişkenlerini kullanmalısınız.

  • Hem tablo değişkenleri hem de geçici tablolar tempdb içinde saklanır. Ancak tablo değişkenleri (2005'ten beri), varsayılan veritabanının varsayılan tempdb ( ref ) harmanlamasını alan geçici tablolara karşı harmanlamasını varsayılan olarak kullanır . Bu geçici tablolar kullanarak db harmanlama tempdb farklıysa, karşılaştırma sorunları farkında olmalıdır geçici tablodaki verileri veritabanınızdaki verilerle karşılaştırmak istiyorsanız sorunlara neden olur.

  • Genel Sıcaklık Tabloları (## tmp), tüm oturumlar ve kullanıcılar tarafından kullanılabilen başka bir geçici tablo türüdür.

Bazı okumalar:


26
Tablo değişkenleri dizinlere sahip olabilir. Sadece benzersiz bir kısıtlama yarattığınızda otomatik olarak bir dizin elde edersiniz. Büyük bir performans farkı yaratır. (Benzersiz bir dizin istemiyorsanız, gerçek birincil anahtarı istediğiniz alanların sonuna eklemeniz yeterlidir. Bir tane yoksa, bir kimlik sütunu oluşturun).
Ben

7
@ Ben ve SQL Server 2014 tablo değişkenleri üzerinde
Martin Smith

4
İşlemlerden etkilenmeyen tablo değişkenleri bazen kullanışlıdır. Bir geri alma işleminden sonra saklamak istediğiniz bir şey varsa, bunu bir tablo değişkenine koyabilirsiniz.
quillbreaker

3
İstatistikler, sorgu planlarını daha iyi hale getirebilen ancak tablo değişkenleri için değil geçici tablolar için oluşturulur. Bu istatistikler, geçici tablo düştükten sonra geçici tablonun sayfaları ile birlikte bir süre önbelleğe alınır ve önbelleğe alınan tablonun yeniden etkinleştirilmesi yanlış olabilir.
Michael Green

Tablo değişkenleri varsayılan olarak ya kullanıcı tanımlı veri türünün harmanlamasını (sütun kullanıcı tanımlı bir veri türündeyse) ya da geçerli veritabanının harmanlamasını (tempdb'nin varsayılan harmanlamasını değil) kullanır. Temp tablolarında tempdb varsayılan harmanlama kullanılır. Bkz: technet.microsoft.com/en-us/library/ms188927.aspx
PseudoToad

25

Sadece kabul edilen cevaptaki tablo değişkenlerinin günlüğe katılmadığı iddiasına bakarak.

O en az günlük miktarı herhangi bir fark (olduğu genellikle yanlış görünüyor insert/ update/ deleteoperasyonlar masaya kendisi ben olsa için bulduğundan beri saklı prosedürler önbelleğe geçici nesneler için bu konuda bazı küçük farklar nedeniyle ek sistem tabloya olduğunu güncellemeleri).

Her iki a karşı Günlüğün çalışma baktı @table_variableve bir #tempaşağıdaki işlemleri için masaya.

  1. Başarılı Ekleme
  2. Çok Sıralı Eklenti, kısıtlama ihlali nedeniyle geri alındı.
  3. Güncelleme
  4. Sil
  5. ayırması

İşlem günlüğü kayıtları tüm işlemler için neredeyse aynıydı.

Tablo değişkeni sürümü aslında birkaç ek günlük girişine sahiptir, çünkü sys.syssingleobjrefstemel tabloya eklenen (ve daha sonra kaldırılan) bir girdi alır, ancak genel olarak tablo değişkenleri için dahili ad #temptablolara göre 236 daha az bayt tükettiğinden genel olarak birkaç gün daha az bayt içerir. (118 daha az nvarcharkarakter).

(Tek kullanıcı modu ve kullanma başlayan bir örneği en iyi çalışma üretmesidir Tam komut sqlcmdmodu)

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

Sonuçlar

+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
|                       |                    |                           |             @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 Sadece meraktan (ve biraz bilgiç olmak). Soru oldukça eskiydi (Ağu 2008), bu yüzden SQL 2005'le ilgiliydi. Şimdi 2011'de (sonu) ve en son SQL 2008 R2 artı Denali beta. Hangi sürümü kullandınız?
xanatos

2
@xanatos - 2008. 2005'te INSERT ... SELECT, minimal olarak günlüğe kaydedilmediğinden tablo değişkenleri aslında dezavantajlı olacaktır ve SELECT INTO ... tablo değişkeni yapamazsınız .
Martin Smith

1
Teşekkürler @MartinSmith, günlük kaydıyla ilgili iddiayı kaldırmak için cevabımı güncelledi.
Rory

18

Biri hangi senaryolarda diğerini gerçekleştiriyor?

Daha küçük tablolar için (1000 satırdan az) geçici değişken kullanın, aksi takdirde geçici tablo kullanın.


17
Herhangi bir destekleyici veri var mı? Bu sadece kendi başına bir iddia olarak çok yararlı değil.
Michael Myers

8
Microsoft 100 satır sınırı önerir: msdn.microsoft.com/en-us/library/ms175010.aspx (En İyi Uygulamalar bölümüne bakın).
Artemix

Benim Bkz cevabı açıklama için aşağıya.
Weihui Guo

17

@wcm - aslında Tablo Değişkeni'ni nit olarak seçmek için yalnızca Ram değil - kısmen diskte saklanabilir.

Bir geçici tablonun dizinleri olabilir, oysa bir tablo değişkeninin yalnızca birincil dizini olabilir. Hız bir sorunsa Tablo değişkenleri daha hızlı olabilir, ancak açıkçası çok fazla kayıt varsa veya kümelenmiş bir dizinin geçici tablosunda arama yapılması gerekiyorsa, bir Temp Tablosu daha iyi olur.

İyi arka plan makalesi


2
İyi arka plan makalesi +1. Çok fazla ayrılmayacağını ve zaten çok iyi cevaplar
verdiğinden cevabımı sileceğim

12
  1. Geçici tablo: Geçici tablo oluşturmak ve verileri yedeklemek kolaydır.

    Tablo değişkeni: Ancak tablo değişkeni, genellikle normal tabloları oluştururken gösterilen çabayı içerir.

  2. Temp tablosu: Temp tablosu sonucu birden çok kullanıcı tarafından kullanılabilir.

    Tablo değişkeni: Ancak tablo değişkeni yalnızca geçerli kullanıcı tarafından kullanılabilir. 

  3. Temp tablosu: Temp tablosu tempdb'de saklanır. Ağ trafiği oluşturacaktır. Temp tablosunda büyük veriler olduğunda, veritabanında çalışması gerekir. Bir Performans sorunu olacaktır.

    Tablo değişkeni: Ancak bir tablo değişkeni bazı veriler için fiziksel bellekte depolanır, daha sonra boyut arttığında tempdb'ye taşınır.

  4. Temp tablosu: Temp tablosu tüm DDL işlemlerini yapabilir. Dizin oluşturma, bırakma, değiştirme vb.

    Tablo değişkeni: Tablo değişkeni DDL işlemlerine izin vermez. Ancak table değişkeni yalnızca kümelenmiş dizini oluşturmamıza izin verir.

  5. Geçici tablo: Geçici tablo geçerli oturum için veya genel olarak kullanılabilir. Böylece çoklu kullanıcı oturumu tablodaki sonuçları kullanabilir.

    Tablo değişkeni: Ancak tablo değişkeni bu programa kadar kullanılabilir. (Saklı yordam)

  6. Temp tablosu: Temp değişkeni işlemleri kullanamaz. Geçici tablo ile DML işlemlerini yaptığımızda, geri alma veya işlemleri gerçekleştirebiliriz.

    Tablo değişkeni: Ancak bunu tablo değişkeni için yapamayız.

  7. Temp tablosu: İşlevler temp değişkenini kullanamaz. Dahası, fonksiyonlarda DML işlemini yapamayız.

    Tablo değişkeni: Ancak işlev, tablo değişkenini kullanmamıza izin verir. Ancak tablo değişkenini kullanarak bunu yapabiliriz.

  8. Temp tablosu: Her alt sıralı çağrı için temp değişkenini kullandığımızda saklı yordam yeniden derleme yapar (aynı yürütme planını kullanamaz).

    Tablo değişkeni: Tablo değişkeni böyle yapmaz.


8

Geçici değişkenlerin sadece hafızada olduğuna dair efsaneye inanan herkes için

İlk olarak, table değişkeni mutlaka bellekte yerleşik DEĞİLDİR. Bellek baskısı altında, bir tablo değişkenine ait sayfalar tempdb'ye itilebilir.

Makaleyi buradan okuyun: TempDB :: Tablo değişkeni vs yerel geçici tablo


3
Yanıtlarınızı iki noktayı ele alan tek bir cevapta düzenleyebilir misiniz?
Joshua Drake

7

Diğer temel fark, tablo değişkenlerinin geçici tablolar gibi sütun istatistiklerine sahip olmamasıdır. Bu, sorgu eniyileyicisinin tablo değişkeninde kaç satır olduğunu bilmediği anlamına gelir (1'i tahmin eder).


2
rowsSütun sys.partitionsaslında tabloda kaç satır biliyor böylece tablo değişkenleri için korunur. Bunu kullanarak görülebilir OPTION (RECOMPILE). Ancak sütun istatistiklerinin olmaması, belirli sütun tahminlerini tahmin edemeyeceği anlamına gelir.
Martin Smith

7

Alıntı alınan; Profesyonel SQL Server 2012 Dahili ve Sorun Giderme

İstatistik Geçici tablolar ve tablo değişkenleri arasındaki en büyük fark, istatistiklerin tablo değişkenleri üzerinde oluşturulmamasıdır. Bunun iki büyük sonucu vardır; bunların en önemlisi, Sorgu Optimize Edici'nin, içerdiği verilere bakılmaksızın bir tablo değişkenindeki satır sayısı için sabit bir tahmin kullanmasıdır. Ayrıca, veri eklemek veya kaldırmak tahminleri değiştirmez.

endeksleri Kısıtlamalar oluşturabilseniz de, tablo değişkenlerinde dizin oluşturamazsınız. Bu, birincil anahtarlar veya benzersiz kısıtlamalar oluşturarak, tablo değişkenlerinde dizinler (bunlar kısıtlamaları desteklemek için oluşturuldukları için) olabileceğiniz anlamına gelir. Kısıtlamalarınız ve dolayısıyla istatistiklere sahip olan dizinleriniz olsa bile, derleme sorgu sırasında derlendiğinde kullanılmayacaktır, çünkü derleme zamanında bulunmazlar veya yeniden derlemeye neden olmazlar.

Şema Değişiklikleri Şema değişiklikleri geçici tablolarda mümkündür, ancak tablo değişkenlerinde kullanılamaz. Şema değişiklikleri geçici tablolarda mümkün olsa da, tabloları kullanan ifadelerin yeniden derlenmesine neden oldukları için bunları kullanmaktan kaçının.

Geçici Tablolar ve Tablo Değişkenleri

TABLO DEĞİŞKENLERİ BELLEKTE OLUŞTURULMUYOR

Tablo değişkenlerinin bellek içi yapılar olduğu ve bu nedenle geçici tablolardan daha hızlı performans göstereceği konusunda yaygın bir yanlış anlama vardır . Sys adında bir DMV sayesinde. oturuma göre tempdb kullanımını gösteren dm _ db _ oturum _ alan _ kullanımı, durumun böyle olmadığını kanıtlayabilirsiniz . DMV'yi temizlemek için SQL Server'ı yeniden başlattıktan sonra, oturum _ kimliğinizin kullanıcı _ nesneleri _ ayırma _ sayfa _ sayısı için 0 döndürdüğünü doğrulamak için aşağıdaki komut dosyasını çalıştırın:

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

Artık bir sütun ile geçici bir tablo oluşturmak ve bir satırla doldurmak için aşağıdaki komut dosyasını çalıştırarak geçici bir tablonun ne kadar alan kullandığını kontrol edebilirsiniz:

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 ;

Sunucumdaki sonuçlar, tablonun tempdb içinde bir sayfa ayrıldığını gösterir. Şimdi aynı komut dosyasını çalıştırın ancak bu sefer bir tablo değişkeni kullanın:

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 ;

Hangisini Kullanmalı?

Geçici tablolar veya tablo değişkenleri kullanıp kullanmadığınıza kapsamlı bir test yapılarak karar verilmelidir, ancak varsayılan olarak geçici tablolara yaslanmak en iyisidir çünkü yanlış gidebilecek çok daha az şey vardır .

Müşterilerin tablo değişkenlerini kullanarak kod geliştirdiklerini gördüm çünkü az miktarda satırla uğraşıyorlardı ve geçici bir tablodan daha hızlıydı, ancak birkaç yıl sonra tablo değişkeninde yüz binlerce satır vardı ve performans korkunçtu , kararınızı verirken bazı kapasite planlamasına izin verin!


Aslında istatistikler tablo değişkenleri üzerinde oluşturulur, bkz. Stackoverflow.com/questions/42824366/…
YuFeng Shen

4

Başka bir farklılık:

Bir tablo değişkenine, o yordam veya iç içe dinamik SQL (exec veya sp_executesql aracılığıyla) olarak adlandırılan diğer yordamlardan değil, yalnızca onu oluşturan yordamdaki ifadelerden erişilebilir.

Bir geçici tablonun kapsamı, diğer taraftan, çağrılan yordamlar ve iç içe dinamik SQL kod içerir.

Yordamınız tarafından oluşturulan tabloya diğer çağrılan yordamlardan veya dinamik SQL'den erişilebilir olması gerekiyorsa, geçici tablo kullanmalısınız. Bu karmaşık durumlarda çok kullanışlı olabilir.


2

Arasındaki farklar Temporary Tables (##temp/#temp)ve Table Variables (@table)gibidir:

  1. Table variable (@table)içinde oluşturulur memory. Halbuki a ' Temporary table (##temp/#temp)da oluşturulur tempdb database. Bununla birlikte, bir bellek basıncı varsa, bir tablo değişkenine ait sayfalar tempdb'ye itilebilir.

  2. Table variableskatılamaz transactions, logging or locking. Bu yapar @table faster then #temp. Yani tablo değişkeni geçici tablodan daha hızlıdır.

  3. Temporary tableaksine şema değişikliklerine izin verir Table variables.

  4. Temporary tablesoluşturulan rutinde ve ayrıca alt rutinde görülebilir. Oysa, Tablo değişkenleri sadece oluşturulan rutinde görülebilir.

  5. Temporary tablesizin verilen CREATE INDEXesoysa Table variablesizin verilmez CREATE INDEXbunun yerine kullanarak dizini olabilir Primary Key or Unique Constraint.


1

Ayrıca, her ikisini de, daha hızlı olabilen türetilmiş tablolarla değiştirebileceğinizi düşünün. Bununla birlikte, tüm performans ayarlarında olduğu gibi, yalnızca gerçek verilerinize karşı yapılan gerçek testler, sorgunuz için en iyi yaklaşımı size söyleyebilir.


1

Bu ikisi arasındaki temel farkın hiç kimsenin, geçici tablonun paralel girişi desteklerken , tablo değişkeni olmadığı konusunda beni şaşırtması beni şaşırttı . Uygulama planından farkı görebilmelisiniz. İşte Kanal 9'daki SQL Workshops'un videosu .

Bu aynı zamanda SQLMenace'in daha önce yanıtladığı gibi neden daha küçük tablolar için geçici değişken kullanmanız gerektiğini, aksi halde geçici tablo kullanmanız gerektiğini de açıklar .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.