While temporary tables (in my opinion) are far better than cursors, they do cause a performance hit when being used.
Temporary tables slow performance dramatically. The problem with temporary tables is the amount of overhead that goes along with using them. In order to get the fastest queries possible, our goal must be to make them do as little work as possible. For example, with a SELECT statement, SQL Server reads data from the disk and returns the data. However, temporary tables require the system to do much more.For example, a piece of Transact-SQL code using temporary tables usually will:
1) CREATE the temporary table
2) INSERT data into the newly created table
3) SELECT data from the temporary table (usually by JOINing to other physical tables) while holding a lock on the entire tempdb database until the transaction has completed. 4) DROP the temporary table
This represents a lot of disk activity, along with the potential for contention problems. And all of this adds up to poor performance.
As queries become more complex, temporary tables are used more and more. While temporary table may sometimes be unavoidable, they can often be sidestepped by using derived tables instead. In brief, a derived table is the result of using another SELECT statement in the FROM clause of a SELECT statement. By using derived tables instead of temporary tables, we can boost our application's performance.
The biggest benefit of using derived tables over using temporary tables is that they require fewer steps, and everything happens in memory instead of a combination of memory and disk. The fewer the steps involved, along with less I/O, the faster the performance.Here are the steps when you use a temporary table:
1) Lock tempdb database
2) CREATE the temporary table (write activity)
3) SELECT data & INSERT data (read & write activity)
4) SELECT data from temporary table and permanent table(s) (read activity)
5) DROP TABLE (write activity)
6) Release the locks
Compare the above to the number of steps it takes for a derived table:
1) CREATE locks, unless isolation level of "read uncommitted" is used
2) SELECT data (read activity)
3) Release the locks
As is rather obvious from this example, using derived tables instead of temporary tables reduces disk I/O and can boost performance.
Derived tables are essentially SELECT statements within SELECT statements.
Let's look at a very simple example:
Take a look at this simple query where we SELECT data from a table:
USE northwind
GO
SELECT * FROM categories
Now, instead of selecting data from the categories table, let’s select our data from a derived table. For example:
USE northwind
GO
SELECT * FROM (SELECT * FROM categories) dt_categories
This is all there is to derived tables. Remember, a derived table is just the result of using another SELECT statement in the FROM clause of another SELECT statement. Simply put the query in parenthesis and add a table name after the query in the parenthesis.
If You Do Use Temporary Tables, Optimize Their Use
If the situation mandates the use of a temporary table, then there are several things you can do to maximize their performance.
First, just because it is a temporary table do not be tempted to put all the columns and all the rows from your permanent table into the temporary table if you do not need them. Filter the data going into your temporary table to include the minimum number of columns and rows actually needed.
Second, do not use the SELECT INTO statement to create your temp table. The SELECT INTO should be avoided at all costs in your coding due to the locking it places on system objects while it determines how to build the table. Take the time to script the temporary table out and use a separate INSERT INTO to populate the table.
I will qualify this with that you can use a SELECT INTO if it includes WHERE 1=0 to create a table in the quickest way possible, but don't do this just to save a few keystrokes.
Third, watch how you use temporary tables to avoid recompiles on the stored procedure.
Fourth, test the need for a clustered-index on your temporary table. If the data set is large, a cluster-index will speed the operations against the temporary table, but you have to weigh the performance needs of creating that index and inserting data into a table with a clustered-index. This is one of those methods that needs to be tested both ways, with the largest data set you think will be placed into the temporary table, before deciding on the index.
And last, I know that when the stored procedure completes and the connection ends, the temporary table will be dropped, but why keep it around if you are done with it. If you code creates and uses a temporary table, and then goes on to do other things that do not involve that table drop the table when you are done. This frees up tempdb resources for other objects. I will even drop the table at the end of a stored procedure even though the connection is about to finish just to avoid any issues that may arise with unknown bugs.
![[bandito] [bandito] [bandito]](/data/assets/smilies/bandito.gif)
[blue]DBomrrsm[/blue]
[blue]Software code, like laws and sausages, should never be examined in production[/blue][black] - [/black][purple]Edward Tenner[/purple]