ความแตกต่างระหว่างโต๊ะ temp และตัวแปร table ใน SQL Server คืออะไร?


390

ใน SQL Server 2005 เราสามารถสร้าง temp tables หนึ่งในสองวิธี:

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

หรือ

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

ความแตกต่างระหว่างสองสิ่งนี้คืออะไร? ฉันได้อ่านความคิดเห็นที่ขัดแย้งกันว่า @tmp ยังคงใช้ tempdb หรือไม่หรือทุกอย่างเกิดขึ้นในหน่วยความจำ

ในสถานการณ์ใดที่ไม่สามารถทำได้อีก



2
มีการเขียนที่ดีจริงๆโดย Pinal Dave ที่นี่ ... blog.sqlauthority.com/2009/12/15/…
sam yi

คำตอบ:


392

มีความแตกต่างเล็กน้อยระหว่าง Temporary Tables (#tmp) และ Table Variables (@tmp) แม้ว่าการใช้ tempdb ไม่ใช่หนึ่งในนั้นดังที่สะกดไว้ในลิงก์ MSDN ด้านล่าง

ตามกฎทั่วไปแล้วสำหรับข้อมูลขนาดเล็กถึงขนาดกลางและสถานการณ์การใช้งานอย่างง่ายคุณควรใช้ตัวแปรตาราง (นี่เป็นแนวทางที่กว้างเกินไปซึ่งมีข้อยกเว้นมากมายแน่นอน - ดูบทความด้านล่างและบทความต่อไปนี้)

บางจุดที่ควรพิจารณาเมื่อเลือกระหว่าง:

  • ตารางชั่วคราวเป็นตารางจริงดังนั้นคุณสามารถทำสิ่งต่าง ๆ เช่นสร้างดัชนี ฯลฯ หากคุณมีข้อมูลจำนวนมากซึ่งการเข้าถึงโดยดัชนีจะเร็วกว่าตารางชั่วคราวจึงเป็นตัวเลือกที่ดี

  • ตัวแปรตารางสามารถมีดัชนีได้โดยใช้ Primary KEY หรือ UNIQUE ข้อ จำกัด (หากคุณต้องการให้ดัชนีที่ไม่ซ้ำกันเพียงรวมคอลัมน์คีย์หลักเป็นคอลัมน์สุดท้ายในข้อ จำกัด ที่ไม่ซ้ำกันหากคุณไม่มีคอลัมน์ที่ไม่ซ้ำคุณสามารถใช้คอลัมน์ข้อมูลประจำตัว) SQL 2014 มีดัชนีที่ไม่ซ้ำกันด้วย .

  • ตัวแปรตารางไม่ได้มีส่วนร่วมในการทำธุรกรรมและSELECTs NOLOCKมีโดยปริยายด้วย พฤติกรรมการทำธุรกรรมจะมีประโยชน์มากเช่นหากคุณต้องการย้อนกลับไปตรงกลางผ่านขั้นตอนแล้วตัวแปรตารางที่เติมระหว่างการทำธุรกรรมนั้นจะยังคงมีอยู่!

  • ตารางชั่วคราวอาจส่งผลให้กระบวนการที่เก็บไว้ถูกคอมไพล์ใหม่บ่อยครั้ง ตัวแปรตารางจะไม่

  • คุณสามารถสร้างตารางชั่วคราวโดยใช้ SELECT INTO ซึ่งสามารถเขียนได้เร็วกว่า (ดีสำหรับการสอบถามแบบเฉพาะกิจ) และอาจช่วยให้คุณสามารถจัดการกับการเปลี่ยนแปลงประเภทข้อมูลในช่วงเวลาหนึ่งเนื่องจากคุณไม่จำเป็นต้องกำหนดโครงสร้างตารางชั่วคราวของคุณ

  • คุณสามารถส่งผ่านตัวแปรตารางกลับจากฟังก์ชั่นทำให้คุณสามารถห่อหุ้มและนำตรรกะกลับมาใช้ใหม่ได้ง่ายขึ้น (เช่นทำให้ฟังก์ชั่นแยกสตริงเป็นตารางค่าในตัวคั่นบางตัว)

  • การใช้ตัวแปรตารางภายในฟังก์ชั่นที่ผู้ใช้กำหนดจะทำให้สามารถใช้งานฟังก์ชั่นเหล่านั้นได้อย่างกว้างขวางมากขึ้น (ดูที่การสร้างเอกสารประกอบการทำงานสำหรับรายละเอียด) หากคุณกำลังเขียนฟังก์ชั่นคุณควรใช้ตัวแปรตารางเหนือตารางชั่วคราวเว้นแต่จะมีความต้องการที่น่าสนใจ

  • ทั้งตัวแปรตารางและตารางชั่วคราวถูกเก็บไว้ใน tempdb แต่ตัวแปรตาราง (ตั้งแต่ปี 2005) เริ่มต้นในการเปรียบเทียบของฐานข้อมูลปัจจุบันกับตารางชั่วคราวซึ่งใช้การเปรียบเทียบเริ่มต้นของ tempdb ( อ้างอิง ) ซึ่งหมายความว่าคุณควรตระหนักถึงปัญหาการเรียงหากใช้ temp tables และการเปรียบเทียบ db ของคุณนั้นแตกต่างจาก tempdb's ทำให้เกิดปัญหาหากคุณต้องการเปรียบเทียบข้อมูลในตาราง temp กับข้อมูลในฐานข้อมูลของคุณ

  • Global Temp Tables (## tmp) เป็นตาราง temp ประเภทอื่นที่มีให้สำหรับทุกเซสชันและผู้ใช้

อ่านเพิ่มเติมบางส่วน:


26
ตัวแปรตารางสามารถมีดัชนีได้ เพียงสร้างข้อ จำกัด ที่ไม่ซ้ำใครและคุณจะได้รับดัชนีโดยอัตโนมัติ สร้างความแตกต่างด้านประสิทธิภาพอย่างมาก (หากคุณไม่ต้องการดัชนีที่ไม่ซ้ำให้เพิ่มคีย์หลักจริงที่ท้ายฟิลด์ที่คุณต้องการหากคุณยังไม่มีให้สร้างคอลัมน์ข้อมูลประจำตัว)
Ben

7
@Ben และ SQL Server 2014 อนุญาตให้ระบุ
Martin Smith

4
ตัวแปรตารางที่ไม่ได้รับผลกระทบจากการทำธุรกรรมบางครั้งก็สะดวก หากคุณมีสิ่งใดที่คุณต้องการเก็บไว้หลังจากย้อนกลับคุณสามารถวางไว้ในตัวแปรตารางได้
quillbreaker

3
สถิติถูกสร้างขึ้นสำหรับตารางชั่วคราวซึ่งสามารถทำให้แผนแบบสอบถามดีขึ้น แต่ไม่ใช่สำหรับตัวแปรตาราง สถิติเหล่านี้ถูกแคชชั่วขณะหนึ่งพร้อมกับหน้าของตาราง temp หลังจากตาราง temp ถูกดร็อปและอาจไม่ถูกต้องหากตารางแคชถูกเปิดใช้งานอีกครั้ง
Michael Green

ตัวแปรตารางจะใช้ค่าเริ่มต้นในการเปรียบเทียบประเภทข้อมูลที่ผู้ใช้กำหนด (หากคอลัมน์เป็นประเภทข้อมูลที่ผู้ใช้กำหนด) หรือการเปรียบเทียบฐานข้อมูลปัจจุบันและไม่ใช่การเปรียบเทียบค่าเริ่มต้นของ tempdb ตารางชั่วคราวจะใช้การเปรียบเทียบเริ่มต้น tempdb ดู: technet.microsoft.com/en-us/library/ms188927.aspx
PseudoToad

25

เพียงแค่ดูการอ้างสิทธิ์ในคำตอบที่ยอมรับแล้วว่าตัวแปรตารางไม่เข้าร่วมในการบันทึก

โดยทั่วไปดูเหมือนว่าไม่จริงว่ามีความแตกต่างในปริมาณของการบันทึก (อย่างน้อยสำหรับinsert/ update/ deleteการดำเนินงานไปยังตารางตัวเองแม้ว่าฉันได้พบตั้งแต่มีความแตกต่างเล็กน้อยในส่วนนี้สำหรับวัตถุชั่วคราวแคชในกระบวนงานที่เก็บไว้เนื่องจากตารางระบบเพิ่มเติม การปรับปรุง)

ฉันดูพฤติกรรมการบันทึกกับทั้ง a @table_variableและ#tempตารางสำหรับการดำเนินการต่อไปนี้

  1. แทรกสำเร็จ
  2. การแทรกหลายแถวโดยที่คำสั่งย้อนกลับเนื่องจากการละเมิดข้อ จำกัด
  3. ปรับปรุง
  4. ลบ
  5. deallocate

บันทึกการทำธุรกรรมเกือบจะเหมือนกันสำหรับการดำเนินการทั้งหมด

เวอร์ชันตัวแปรตารางมีรายการบันทึกเพิ่มเติมสองสามรายการเนื่องจากได้รับรายการเพิ่ม (และลบออกภายหลัง) sys.syssingleobjrefsตารางฐาน แต่โดยรวมมีการบันทึกไบต์น้อยกว่าเล็กน้อยโดยแท้เนื่องจากชื่อภายในสำหรับตัวแปรตารางใช้ 236 ไบต์น้อยกว่าสำหรับ#tempตาราง (118 nvarcharตัวอักษรน้อยลง)

สคริปต์เต็มรูปแบบที่จะทำซ้ำ (ทำงานได้ดีที่สุดในอินสแตนซ์ที่เริ่มต้นในโหมดผู้ใช้คนเดียวและใช้sqlcmdโหมด)

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

ผล

+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
|                       |                    |                           |             @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 เพิ่งเกิดความอยากรู้อยากเห็น (และอยากรู้อยากเห็นสักหน่อย) คำถามคือ / ค่อนข้างเก่า (สิงหาคม 2008) ดังนั้นจึงเกี่ยวกับ SQL 2005 ตอนนี้เราอยู่ใน 2011 (สิ้นสุด) และ SQL ล่าสุดคือ 2008 R2 บวก Denali เบต้า คุณใช้เวอร์ชันอะไร
xanatos

2
@xanatos - 2008. ในปี 2005 ตัวแปรตารางจะเสียเปรียบจริง ๆ เนื่องจากINSERT ... SELECTไม่ได้ถูกบันทึกอย่างน้อยและคุณไม่สามารถSELECT INTO ... ตัวแปรตารางได้
Martin Smith

1
ขอบคุณ @MartinSmith อัปเดตคำตอบของฉันเพื่อลบการอ้างสิทธิ์เกี่ยวกับการเข้าสู่ระบบ
Rory

18

ในสถานการณ์ใดที่ไม่สามารถทำได้อีก

สำหรับตารางที่เล็กกว่า (น้อยกว่า 1,000 แถว) ให้ใช้ตัวแปรชั่วคราวมิฉะนั้นใช้ตารางชั่วคราว


17
มีข้อมูลสนับสนุนใดบ้าง สิ่งนี้ไม่ได้มีประโยชน์มากนักเหมือนกับการยืนยันตัวเอง
Michael Myers

8
Microsoft แนะนำขีด จำกัด 100 แถว: msdn.microsoft.com/en-us/library/ms175010.aspx (ดูส่วนวิธีปฏิบัติที่ดีที่สุด)
Artemix

ดูคำตอบของฉันด้านล่างสำหรับคำอธิบาย
Weihui Guo

17

@wcm - จริง ๆ แล้วจะเลือกตัวแปรตารางไม่ใช่เพียง Ram - สามารถเก็บไว้ในดิสก์ได้บางส่วน

ตาราง temp สามารถมีดัชนีได้ในขณะที่ตัวแปร table สามารถมีดัชนีหลักได้เท่านั้น ถ้า speed เป็นปัญหาตัวแปร Table สามารถเร็วขึ้น แต่เห็นได้ชัดว่ามีเร็กคอร์ดจำนวนมากหรือต้องการค้นหาเทมเพลต temp ของดัชนีแบบคลัสเตอร์แล้ว Table Temp จะดีกว่า

บทความพื้นหลังที่ดี


2
บทความพื้นหลังที่ดี +1 ฉันจะลบคำตอบของฉันตั้งแต่การแก้ไขมันจะไม่ทิ้งไปมากและมีคำตอบที่ดีมากมายอยู่แล้ว
wcm

12
  1. ตารางชั่วคราว: ตารางชั่วคราวสร้างและสำรองข้อมูลได้ง่าย

    ตัวแปรตาราง: แต่ตัวแปรตารางเกี่ยวข้องกับความพยายามเมื่อเรามักจะสร้างตารางปกติ

  2. ตารางชั่วคราว: ผลลัพธ์ของตารางชั่วคราวสามารถใช้งานได้โดยผู้ใช้หลายคน

    ตัวแปรตาราง: แต่ตัวแปรตารางสามารถใช้งานได้โดยผู้ใช้ปัจจุบันเท่านั้น 

  3. ตารางชั่วคราว: ตารางชั่วคราวจะถูกเก็บไว้ใน tempdb มันจะทำให้การรับส่งข้อมูลเครือข่าย เมื่อเรามีข้อมูลขนาดใหญ่ในตาราง temp มันจะต้องทำงานข้ามฐานข้อมูล ปัญหาประสิทธิภาพจะมีอยู่

    ตัวแปรตาราง: แต่ตัวแปรตารางจะเก็บไว้ในหน่วยความจำกายภาพสำหรับข้อมูลบางส่วนจากนั้นเมื่อขนาดเพิ่มขึ้นมันจะถูกย้ายไปที่ tempdb

  4. ตารางชั่วคราว: ตารางชั่วคราวสามารถทำการดำเนินการ DDL ทั้งหมด จะช่วยให้การสร้างดัชนีลดลงเปลี่ยนแปลง ฯลฯ ..

    ตัวแปรตาราง: ในขณะที่ตัวแปรตารางไม่อนุญาตให้ทำการดำเนินการ DDL แต่ตัวแปรตารางช่วยให้เราสามารถสร้างดัชนีคลัสเตอร์เท่านั้น

  5. ตารางชั่วคราว: ตารางชั่วคราวสามารถใช้สำหรับเซสชันปัจจุบันหรือทั่วโลก เพื่อให้ผู้ใช้หลายเซสชันสามารถใช้ผลลัพธ์ในตารางได้

    ตัวแปรตาราง: แต่ตัวแปรตารางสามารถใช้กับโปรแกรมนั้นได้ (ขั้นตอนการเก็บ)

  6. ตารางชั่วคราว: ตัวแปรชั่วคราวไม่สามารถใช้ธุรกรรม เมื่อเราทำการดำเนินการ DML ด้วยตาราง temp มันสามารถย้อนกลับหรือกระทำธุรกรรม

    ตัวแปรตาราง: แต่เราไม่สามารถทำได้สำหรับตัวแปรตาราง

  7. ตารางชั่วคราว: ฟังก์ชั่นไม่สามารถใช้ตัวแปรชั่วคราว ยิ่งกว่านั้นเราไม่สามารถทำการดำเนินการ DML ในฟังก์ชั่นได้

    ตัวแปรตาราง: แต่ฟังก์ชันทำให้เราสามารถใช้ตัวแปรตารางได้ แต่การใช้ตัวแปรตารางเราสามารถทำได้

  8. ตารางชั่วคราว: โพรซีเดอร์ที่เก็บไว้จะทำการคอมไพล์ใหม่ (ไม่สามารถใช้แผนการดำเนินการเดียวกัน) เมื่อเราใช้ตัวแปร temp สำหรับการโทรตามลำดับย่อยทุกครั้ง

    ตัวแปรตาราง: ในขณะที่ตัวแปรตารางจะไม่ทำเช่นนั้น


8

สำหรับคุณทุกคนที่เชื่อในตำนานว่าตัวแปร temp อยู่ในความทรงจำเท่านั้น

ก่อนอื่นตัวแปรตารางไม่จำเป็นต้องอยู่ในหน่วยความจำ ภายใต้ความกดดันของหน่วยความจำเพจที่เป็นของตัวแปรตารางสามารถส่งออกไปยัง tempdb

อ่านบทความที่นี่: TempDB :: Table table vs local temporary table


3
คุณสามารถแก้ไขคำตอบของคุณให้เป็นคำตอบเดียวซึ่งพูดถึงสองประเด็นได้หรือไม่?
Joshua Drake

7

ข้อแตกต่างที่สำคัญอื่น ๆ คือตัวแปรตารางไม่มีสถิติคอลัมน์โดยที่ตาราง temp ทำ ซึ่งหมายความว่าเคียวรีเครื่องมือเพิ่มประสิทธิภาพไม่ทราบว่ามีกี่แถวในตัวแปรตาราง (ซึ่งเดาได้ 1) ซึ่งสามารถนำไปสู่แผนการที่ไม่เหมาะสมที่สุดที่สร้างขึ้นหากตัวแปรตารางมีแถวจำนวนมาก


2
rowsคอลัมน์sys.partitionsเพื่อรักษาตัวแปรตารางจึงไม่จริงรู้วิธีการหลายแถวในตาราง OPTION (RECOMPILE)นี้สามารถเห็นได้โดยใช้ แต่การขาดสถิติคอลัมน์หมายความว่ามันไม่สามารถประมาณค่าคอลัมน์ที่ระบุได้
Martin Smith

7

อ้างจาก; Professional SQL Server 2012 Internals และการแก้ไขปัญหาเบื้องต้น

สถิติ ความแตกต่างที่สำคัญระหว่างตาราง temp และตัวแปร table คือสถิติไม่ได้ถูกสร้างขึ้นบนตัวแปร table สิ่งนี้มีผลกระทบที่สำคัญสองประการอันดับแรกคือเครื่องมือเพิ่มประสิทธิภาพข้อความค้นหาใช้การประเมิน fi xed สำหรับจำนวนแถวในตัวแปรตารางโดยไม่คำนึงถึงข้อมูลที่มีอยู่ ยิ่งกว่านั้นการเพิ่มหรือลบข้อมูลไม่เปลี่ยนการประมาณ

ดัชนีคุณไม่สามารถสร้างดัชนีในตัวแปรตารางได้แม้ว่าคุณจะสามารถสร้างข้อ จำกัด ได้ ซึ่งหมายความว่าโดยการสร้างคีย์หลักหรือข้อ จำกัด ที่ไม่ซ้ำกันคุณสามารถมีดัชนี (เนื่องจากถูกสร้างขึ้นเพื่อรองรับข้อ จำกัด ) ในตัวแปรตาราง แม้ว่าคุณจะมีข้อ จำกัด ดังนั้นดัชนีที่จะมีสถิติดัชนีจะไม่ถูกใช้เมื่อรวบรวมแบบสอบถามเนื่องจากไม่มีอยู่ในเวลารวบรวมและจะไม่ทำให้เกิดการคอมไพล์ใหม่

การปรับเปลี่ยน Schema การแก้ไข Schema สามารถทำได้ในตารางชั่วคราว แต่ไม่สามารถใช้กับตัวแปรของตารางได้ แม้ว่า schema modifi cation นั้นเป็นไปได้ในตารางชั่วคราวหลีกเลี่ยงการใช้มันเพราะมันจะทำให้เกิดการคอมไพล์ใหม่ของคำสั่งที่ใช้ตาราง

ตารางชั่วคราวเมื่อเทียบกับตัวแปรตาราง

ตัวแปรของตารางไม่ได้ถูกสร้างขึ้นในหน่วยความจำ

มีความเข้าใจผิดกันคือตัวแปรตารางมีโครงสร้างในหน่วยความจำและเป็นเช่นนี้จะดำเนินการได้เร็วกว่าตารางชั่วคราว ขอบคุณ DMV ที่เรียกว่า sys DM _ _ DB เซสชั่น _ _ พื้นที่การใช้งานซึ่งแสดงให้เห็นว่า tempdb การใช้งานโดยเซสชั่นที่คุณสามารถพิสูจน์ได้ว่าไม่ได้กรณีที่ หลังจากรีสตาร์ท SQL Server เพื่อล้าง DMV ให้เรียกใช้สคริปต์ต่อไปนี้เพื่อยืนยันว่าเซสชัน _ id ของคุณส่งคืน 0 สำหรับผู้ใช้ _ objects _ alloc _ alloc _ page _ count:

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

ตอนนี้คุณสามารถตรวจสอบจำนวนเนื้อที่ที่ตารางชั่วคราวใช้โดยเรียกใช้สคริปต์ต่อไปนี้เพื่อสร้างตารางชั่วคราวด้วยหนึ่งคอลัมน์และเติมด้วยแถวเดียว:

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 ;

ผลลัพธ์บนเซิร์ฟเวอร์ของฉันระบุว่าตารางได้รับการจัดสรรหนึ่งหน้าใน tempdb ตอนนี้เรียกใช้สคริปต์เดียวกัน แต่ใช้ตัวแปรตารางในครั้งนี้:

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 ;

จะใช้อันไหนดี?

ไม่ว่าคุณจะใช้ตารางชั่วคราวหรือตัวแปรตารางควรจะตัดสินใจโดยการทดสอบอย่างละเอียด แต่ก็เป็นการดีที่สุดที่จะโน้มตัวไปยัง ตาราง ชั่วคราวเป็นค่าเริ่มต้นเนื่องจากมีสิ่งต่าง ๆ ที่อาจผิดพลาดได้

ฉันเคยเห็นลูกค้าพัฒนารหัสโดยใช้ตัวแปรตารางเนื่องจากพวกเขาจัดการกับแถวจำนวนเล็กน้อยและเร็วกว่าตารางชั่วคราว แต่ไม่กี่ปีต่อมามีตัวแปรหลายแสนแถวในตารางและประสิทธิภาพแย่มาก ดังนั้นลองและอนุญาตให้วางแผนกำลังการผลิตเมื่อคุณตัดสินใจ!


ในความเป็นจริงสถิติถูกสร้างขึ้นในตัวแปรตารางดูstackoverflow.com/questions/42824366/…
YuFeng Shen

4

ความแตกต่างอื่น:

ตาราง var สามารถเข้าถึงได้จากคำสั่งภายในโพรซีเดอร์ที่สร้างขึ้นไม่ใช่จากโพรซีเดอร์อื่นที่เรียกใช้โดยโพรซีเดอร์นั้นหรือไดนามิก SQL ที่ซ้อนกัน (ผ่าน exec หรือ sp_executesql)

ในทางกลับกันขอบเขตของตารางเทมเพลตนั้นรวมถึงโค้ดในโพรซีเดอร์ที่เรียกว่าและ SQL แบบไดนามิกที่ซ้อนกัน

หากตารางที่สร้างโดยโพรซีเดอร์ของคุณต้องสามารถเข้าถึงได้จากโพรซีเดอร์ที่เรียกว่าอื่นหรือไดนามิก SQL คุณต้องใช้ตารางอุณหภูมิ สิ่งนี้มีประโยชน์มากในสถานการณ์ที่ซับซ้อน


2

ความแตกต่างระหว่างTemporary Tables (##temp/#temp)และTable Variables (@table)เป็น:

  1. Table variable (@table)memoryถูกสร้างขึ้นใน ในขณะที่ถูกสร้างขึ้นในTemporary table (##temp/#temp) tempdb databaseอย่างไรก็ตามหากมีแรงกดดันหน่วยความจำหน้าเว็บที่เป็นของตัวแปรตารางอาจถูกผลักไปยัง tempdb

  2. Table variablestransactions, logging or lockingไม่สามารถมีส่วนร่วมใน @table faster then #tempนี้จะทำให้ ดังนั้นตัวแปรตารางจึงเร็วกว่าตารางชั่วคราว

  3. Temporary tableอนุญาตให้ปรับเปลี่ยน Schema ไม่เหมือนTable variablesกัน

  4. Temporary tablesสามารถมองเห็นได้ในรูทีนที่สร้างและในรูทีนย่อย ในขณะที่ตัวแปรตารางจะปรากฏเฉพาะในชุดคำสั่งที่สร้างขึ้น

  5. Temporary tablesจะได้รับอนุญาตCREATE INDEXesในขณะที่Table variablesไม่ได้รับอนุญาตแทนพวกเขาสามารถมีดัชนีโดยใช้CREATE INDEXPrimary Key or Unique Constraint


1

พิจารณาด้วยว่าคุณสามารถแทนที่ทั้งสองด้วยตารางที่ได้รับซึ่งอาจเร็วกว่าเช่นกัน เช่นเดียวกับการปรับประสิทธิภาพทั้งหมดการทดสอบจริงกับข้อมูลจริงของคุณเท่านั้นที่สามารถบอกวิธีที่ดีที่สุดสำหรับการสืบค้นเฉพาะของคุณ


1

มันทำให้ฉันประหลาดใจที่ไม่มีใครพูดถึงความแตกต่างที่สำคัญระหว่างสองสิ่งนี้คือตาราง temp รองรับการแทรกแบบขนานในขณะที่ตัวแปรตารางไม่ คุณควรเห็นความแตกต่างจากแผนการดำเนินการ และนี่คือวิดีโอจากการประชุมเชิงปฏิบัติการ SQL ทางช่อง 9

สิ่งนี้ยังอธิบายว่าทำไมคุณควรใช้ตัวแปร temp สำหรับตารางที่เล็กกว่ามิฉะนั้นให้ใช้ตาราง temp ดังที่SQLMenace ตอบก่อน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.