Home A SP FA Q Tutorials
Ads by Google
Temp Agencies Temp Work Variable Annuity Table Function Temp Probes
A SP FA Q Tutorials :: Databases :: Other A rticles :: Should I use a #temp table or a @table v ariable?
Ads by Google
8000XXXX Errors Alerts ASP.NET 2.0 Classic ASP 1.0 Databases Access DB & ADO General SQL Serv er & A ccess A rticles My SQL Other A rticles Schema Tutorials Sql Serv er 2000 Sql Serv er 2005 General Concepts Search Engine Optimization (SEO)
Should I use a #temp table or a @table variable?
In a stored procedure, y ou often hav e a need for storing a set of data within the procedure, without necessarily needing that data to persist bey ond the scope of the procedure. If y ou actually need a table structure, there are basically four way s y ou can "store" this data: local temporary tables (#table_name), global temporary tables (##table_name), permanent tables (table_name), and table v ariables (@table_name). There is a partial list of questions and answers about table v ariables, including some differences between table v ariables and #temp tables, in KB #305977 - INF: Frequently Ask ed Questions - SQL Serv er 2000 - Table Variables. Local Temporary Tables
CREATE TABLE #people ( id INT, name VARCHAR(32) )
Fast Voas Solid-state , 1,4,8 C hanne ls Sub Micro-se cond R e sponse
A temporary table is created and populated on disk , in the sy stem database tempdb — with a session-specific identifier pack ed onto the name, to differentiate between similarly -named #temp tables created from other sessions. The data in this #temp table (in fact, the table itself) is v isible only to the current scope (usually a stored procedure, or a set of nested stored procedures). The table gets cleared up automatically when the current procedure goes out of scope, but y ou should manually clean up the data when y ou're done with it:
DROP TABLE #people
MEDWA Y® Variable Speed Ma nufacture r of Va riable Spe e d Be lts W 16 W 100,13x 6 - 55x 16 size s
This will be better on resources ("release early ") than if y ou let the sy stem clean up *after* the current session finishes the rest of its work and goes out of scope. A common use of #temp tables is to summarize/compact/reorganize data coming from another stored procedure. So, tak e this example, which pares down the results of the sy stem procedure sp_who2 into only the SPID, Status, and HostName of *activ e* processes that are *not* part of the regular operation of the sy stem:
CREATE TABLE #sp_who3 ( SPID INT, Status VARCHAR(32) NULL, Login SYSNAME NULL, HostName SYSNAME NULL, BlkBy SYSNAME NULL, DBName SYSNAME NULL, Command VARCHAR(32) NULL, CPUTime INT NULL, DiskIO INT NULL, LastBatch VARCHAR(14) NULL, ProgramName VARCHAR(32) NULL, SPID2 INT ) INSERT #sp_who3 EXEC sp_who2 'active' SELECT SPID, Status, HostName FROM #sp_who3 WHERE spid > 15 DROP TABLE #sp_who3
VOA , Optical Switch 1-ch, 2-ch VO A, m ulti-ch VO A array 1x 2, 1x 4, 1x 8 O ptical Switch
Newfoil Printing Machines Ma nufacture Hot Foil Labe l Stam ping Die C utting and C onve rting Ma chine s SQL Server ODBC Drivers Q uick & se cure acce ss from Linux , W indows, O SX & othe r Unix O Ss...
Contact Us Site Map Search
One of the main benefits of using a #temp table, as opposed to a permanent table, is the reduction in the amount of lock ing required (since the current user is the only user accessing the table), and also there is much less logging inv olv ed. (You could also increase this performance by placing tempdb on a separate driv e... but that's another story .) One minor problem with #temp tables is that, because of the session-specific identifier that is tack ed onto the name, the name y ou giv e it is limited to 116 characters, including the # sign (while other table ty pes are limited to 128). If y ou try , y ou will see this:
Server: Msg 193, Level 15, State 1, Line 1 The object or column name starting with '#<long string here>' is too long. The maximum length is 116 characters.
Web aspfaq.com tutorials.aspfaq.com databases.aspfaq.com
S earch N ow
Hopefully this won't be a limitation in y our env ironment, because I can't imagine a table name that long being useful or manageable. A nother potential problem with #temp tables is that, if y ou enter a transaction and use a #temp table, and then cancel without ev er issuing a ROLLBA CK or COMMIT, y ou could be causing unnecessary lock s in tempdb (for more information, see KB #159747 ).
Global Temporary Tables
CREATE TABLE ##people ( id INT, name VARCHAR(32) )
Global temporary tables operate much lik e local temporary tables; they are created in tempdb and cause less lock ing and logging than permanent tables. Howev er, they are v isible to all sessions, until the creating session goes out of scope (and the global ##temp table is no longer being referenced by other sessions). If two different sessions try the abov e code, if the first is still activ e, the second will receiv e the following:
Server: Msg 2714, Level 16, State 6, Line 1 There is already an object named '##people' in the database.
I hav e y et to see a v alid justification for the use of a global ##temp table. If the data needs to persist to multiple users, then it mak es much more sense, at least to me, to use a permanent table. You can mak e a global ##temp table slightly more permanent by creating it in an autostart procedure, but I still fail to see how this is adv antageous ov er a permanent table. With a permanent table, y ou can deny permissions; y ou cannot deny users from a global ##temp table. Permanent Tables
CREATE TABLE people ( id INT, name VARCHAR(32) )
A permanent table is created in the local database, howev er y ou can (unlik e #temp tables) choose to create a table in another database, or ev en on another serv er, for which y ou hav e access. Lik e global ##temp tables, a permanent table will persist the session in which it is created, unless y ou also explicitly drop the table. (For contention and concurrency reasons, creating a "temporary " permanent table in this manner doesn't really mak e a lot of sense.) If y ou are planning to create a permanent table when the procedure runs, y ou should check to see if it exists, in order to av oid errors lik e the one mentioned abov e. For more information about check ing for the existence of both local #temp tables and permanent tables, see A rticle #2458 . Lik e global ##temp tables, there seems to be little reason to use a permanent table unless the data is going to persist... and if that is the case, why not create the permanent table before the stored procedure is ev er run, thereby eliminating all the CREA TE / DROP logic? Table Variables
DECLARE @people TABLE ( id INT, name VARCHAR(32) )
A table v ariable is created in memory , and so performs slightly better than #temp tables (also because there is ev en less lock ing and logging in a table v ariable). A table v ariable might still perform I/O to tempdb (which is where the performance issues of #temp tables mak e themselv es apparent), though the documentation is not v ery explicit about this. Table v ariables are automatically cleared when the procedure or function goes out of scope, so y ou don't hav e to remember to drop or clear the data (which can be a good thing or a bad thing; remember "release early "?). The tempdb transaction log is less impacted than with #temp tables; table v ariable log activ ity is truncated immediately , while #temp table log activ ity persists until the log hits a check point, is manually truncated, or when the serv er restarts. Table v ariables are the only way y ou can use DML statements (INSERT, UPDATE, DELETE) on temporary data within a user-defined function. You can create a table v ariable within a UDF, and modify the data using one of the abov e statements. For example, y ou could do this:
CREATE FUNCTION dbo.example1 ( ) RETURNS INT AS BEGIN DECLARE @t1 TABLE (i INT) INSERT @t1 VALUES(1) INSERT @t1 VALUES(2) UPDATE @t1 SET i = i + 5 DELETE @t1 WHERE i < 7 DECLARE @max INT SELECT @max = MAX(i) FROM @t1 RETURN @max END GO
Howev er, try that with a #temp table:
CREATE FUNCTION dbo.example2 ( ) RETURNS INT AS BEGIN CREATE TABLE #t1 (i INT) INSERT #t1 VALUES(1) INSERT #t1 VALUES(2) UPDATE #t1 SET i = i + 5 DELETE #t1 WHERE i < 7 DECLARE @max INT SELECT @max = MAX(i) FROM #t1 RETURN @max END GO
Server: Msg 2772, Level 16, State 1, Procedure example2, Line 7 Cannot access temporary tables from within a function.
Or try accessing a permanent table:
CREATE TABLE table1 ( id INT IDENTITY, name VARCHAR(32) ) GO CREATE FUNCTION dbo.example3 ( ) RETURNS INT AS BEGIN INSERT table1(name) VALUES('aaron') RETURN SCOPE_IDENTITY() END GO
Server: Msg 443, Level 16, State 2, Procedure example3, Line 8 Invalid use of 'INSERT' within a function.
Table v ariables can lead to fewer stored procedure recompilations than temporary tables (see KB #243586 and KB #305977 ), and — since they cannot be rolled back — do not bother with the transaction log. So, why not use table v ariables all the time? W ell, when something sounds too good to be true, it probably is. Let's v isit some of the limitations of table v ariables (part of this list was deriv ed from KB #305977 ): Table v ariables are only allowed in SQL Serv er 2000+, with compatibility lev el set to 80 or higher. You cannot use a table v ariable in either of the following situations:
INSERT @table EXEC sp_someProcedure SELECT * INTO @table FROM someTable
You cannot truncate a table v ariable. Table v ariables cannot be altered after they hav e been declared. You cannot explicitly add an index to a table v ariable, howev er y ou can create a sy stem index through a PRIMA RY KEY C ONSTRAINT, and y ou can add as many indexes v ia UNIQUE C ONSTRA INTs as y ou lik e. What the optimizer does with them is another story . <G> One thing to note is that y ou cannot explicitly name y our constraints, e.g.:
DECLARE @myTable TABLE ( CPK1 int, CPK2 int, CONSTRAINT myPK PRIMARY KEY (CPK1, CPK2) ) -- yields: Server: Msg 156, Level 15, State 1, Line 6 Incorrect syntax near the keyword 'CONSTRAINT'. -- yet the following works: DECLARE @myTable TABLE ( CPK1 int, CPK2 int, PRIMARY KEY (CPK1, CPK2) )
You cannot use a user-defined function (UDF) in a CHECK CONSTRA INT, computed column, or DEFA ULT CONSTRA INT. You cannot use a user-defined ty pe (UDT) in a column definition. Unlik e a #temp table, y ou cannot drop a table v ariable when it is no longer necessary —y ou just need to let it go out of scope. You cannot generate a table v ariable's column list dy namically , e.g. y ou can't do this:
SELECT * INTO @tableVariable -- yields: Server: Msg 170, Level 15, State 1, Line 1 Line 1: Incorrect syntax near '@tableVariable'.
You also can't build the table v ariable inside dy namic SQL, and expect to use it outside that scope, e.g.:
DECLARE @colList VARCHAR(8000), @sql VARCHAR(8000) SET @colList = 'a INT,b INT,c INT' SET @sql = 'DECLARE @foo TABLE('+@colList+')' EXEC(@sql) INSERT @foo SELECT 1,2,3 -- this last line fails: Server: Msg 137, Level 15, State 2, Line 5 Must declare the variable '@foo'.
This is because the rest of the script k nows nothing about the temporary objects created within the dy namic SQL. Lik e other local v ariables, table v ariables declared inside of a dy namic SQL block (EXEC or sp_executeSQL) cannot be referenced from outside, and v ice-v ersa. So y ou would hav e to write the whole set of statements to create and operate on the table v ariable, and perform it with a single call to EXEC or sp_executeSQL. The sy stem will not generate automatic statistics on table v ariables. Lik ewise, y ou cannot manually create statistics (statistics are used to help the optimizer pick the best possible query plan). A n INSERT into a table v ariable will not tak e adv antage of parallelism. A table v ariable will alway s hav e a cardinality of 1, because the table doesn't exist at compile time. Table v ariables must be referenced by an alias, except in the FROM clause. Consider the following two scripts:
CREATE TABLE #foo(id INT) DECLARE @foo TABLE(id INT) INSERT #foo VALUES(1) INSERT #foo VALUES(2) INSERT #foo VALUES(3) INSERT @foo SELECT * FROM #foo SELECT id FROM @foo INNER JOIN #foo ON @foo.id = #foo.id DROP TABLE #foo
The abov e fails with the following error:
Server: Msg 137, Level 15, State 2, Line 11 Must declare the variable '@foo'.
This query , on the other hand, work s fine:
SELECT id FROM @foo f INNER JOIN #foo ON f.id = #foo.id
Table v ariables are not v isible to the calling procedure in the case of nested procs. The following is legal with #temp tables:
CREATE PROCEDURE faq_outer AS BEGIN CREATE TABLE #outer ( letter CHAR(1) ) EXEC faq_inner SELECT letter FROM #outer
DROP TABLE #outer END GO CREATE PROCEDURE faq_inner AS BEGIN INSERT #outer VALUES('a') END GO
letter -----a (1 row(s) affected)
Howev er, y ou cannot do this with table v ariables. The parser will find the error before y ou can ev en create it:
CREATE PROCEDURE faq_outer AS BEGIN DECLARE @outer TABLE ( letter CHAR(1) ) EXEC faq_inner SELECT letter FROM @outer END GO CREATE PROCEDURE faq_inner AS BEGIN INSERT @outer VALUES('a') END GO
Server: Msg 137, Level 15, State 2, Procedure faq_inner, Line 4 Must declare the variable '@outer'.
For more information about sharing data between stored procedures, please see this article by Erland Sommarsk og. Conclusion Lik e many other areas of technology , there is no "right" answer here. For data that is not meant to persist bey ond the scope of the procedure, y ou are ty pically choosing between #temp tables and table v ariables. Your ultimate decision should depend on performance and reasonable load testing. A s y our data size gets larger, and/or the repeated use of the temporary data increases, y ou will find that the use of #temp tables mak es more sense. Depending on y our env ironment, that threshold could be any where — howev er y ou will obv iously need to use #temp tables if any of the abov e limitations represents a significant roadblock .
How do I build a query with optional parameters? How do I calculate the median in a table? How do I create a store locator feature? How do I deal with MEMO, TEXT, HYPERLINK, and CURRENCY columns? How do I deal with multiple resultsets from a stored procedure? How do I debug my SQL statements? How do I determine if a column exists in a giv en table? How do I enable or disable connection pooling? How do I enumerate through the DSNs on a machine? How do I find a stored procedure containing <text>? How do I get a list of Access tables and their row counts? How do I get the latest v ersion of the JET OLEDB driv ers? How do I handle alphabetic paging? How do I handle BIT / BOOLEA N columns? How do I handle error check ing in a stored procedure? How do I ignore common words in a search?
How do I page through a recordset? How do I present one-to-many relationships in my ASP page? How do I prev ent duplicates in a table? How do I prev ent my ASP pages from waiting for back end activ ity ? How do I prev ent NULLs in my database from muck ing up my HTML? How do I protect my Access database (MDB file)? How do I protect my stored procedure code? How do I protect my self against the W32.Slammer worm? How do I remov e duplicates from a table? How do I rename a column? How do I retriev e a random record? How do I return row numbers with my query ? How do I send a database query to a text file? How do I simulate an array inside a stored procedure? How do I solv e 'Could not find installable ISA M' errors? How do I solv e 'Operation must use an updateable query ' errors? How do I temporarily disable a trigger? How do I use a SELEC T list alias in the WHERE or GROUP BY clause? How do I use a v ariable in an ORDER BY clause? Should I index my database table(s), and if so, how? Should I store images in the database or the filesy stem? Should I use a v iew, a stored procedure, or a user-defined function? Should I use recordset iteration, or GetRows(), or GetString()? What are all these dt_ stored procedures, and can I remov e them? What are the limitations of MS A ccess? What are the limitations of MSDE? What are the v alid sty les for conv erting datetime to string? What dataty pe should I use for my character-based database columns? What dataty pe should I use for numeric columns? What does "ambiguous column name" mean? What is this 'Multiple-step OLE DB' error? What is wrong with 'SELECT *'? What naming conv ention should I use in my database? What should I choose for my primary k ey ? What should my connection string look lik e? When should I use CreateObject to create my recordset objects? Where can I get this 'Book s Online' documentation? Where do I get MSDE? Which database platform should I use for my A SP application? Which tool should I use: Enterprise Manager or Query A naly zer? Why are there gaps in my IDENTITY / AUTO INCREMENT column? Why can I not 'open a database created with a prev ious v ersion...'? Why can't I access a database or text file on another serv er? Why can't I use the TOP k ey word? Why do I get 'A rgument data ty pe text is inv alid for argument [...]'? Why do I get 'Not enough space on temporary disk ' errors? Why does A SP giv e me A ctiv eX errors when connecting to a database? Should I use C OALESCE() or ISNULL()? Where can I get basic info about using stored procedures?