Optimizing temporary tables

Many uses of temporary tables are simple and brief and require little optimization. However, if your applications require multiple accesses to tables in a temporary database, examine them for possible optimization strategies. Usually, this involves splitting out the creation and indexing of the table from the access to it by using more than one procedure or batch.

When you create a table in the same stored procedure or batch where it is used, the query optimizer cannot determine how large the table is because the table was not created when the query was optimized, as shown in Figure 6-3. This applies to both temporary tables and regular user tables.

Figure 6-3: Optimizing and creating temporary tables

Image shows a flow chart of how a temporary table is optimized and created: The query runs, and is parsed and normalized. The query is optimized then compiled, executed (at this point the table is created), and then the result set is printed.

The optimizer assumes that any such table has 10 data pages and 100 rows. If the table is really large, this assumption can lead the optimizer to choose a suboptimal query plan.

These two techniques can improve the optimization of temporary tables:


Creating indexes on temporary tables

You can define indexes on temporary tables. In many cases, these indexes can improve the performance of queries that use temporary databases. The optimizer uses these indexes just like indexes on ordinary user tables. The only requirements are:

Providing an index for the optimizer can greatly increase performance, especially in complex procedures that create temporary tables and then perform numerous operations on them.


Creating nested procedures with temporary tables

You need to take an extra step to create the procedures described above. You cannot create base_proc until select_proc exists, and you cannot create select_proc until the temporary table exists.

  1. Create the temporary table outside the procedure. It can be empty; it just must exist and have columns that are compatible with select_proc:

    select * into #huge_result from ... where 1 = 2
    
  2. Create the procedure select_proc, as shown above.

  3. Drop #huge_result.

  4. Create the procedure base_proc.


Breaking tempdb uses into multiple procedures

For example, this query causes optimization problems with #huge_result:

create proc base_proc 
as
    select * 
        into #huge_result 
        from ...
    select * 
        from tab, 
        #huge_result where ...

You can achieve better performance by using two procedures. When the base_proc procedure calls the select_proc procedure, the optimizer can determine the size of the table:

create proc select_proc 
as
    select * 
        from tab, #huge_result where ...
create proc base_proc 
as
    select * 
        into #huge_result 
        from ...
    exec select_proc

If the processing for #huge_result requires multiple accesses, joins, or other processes (such as looping with while), creating an index on #huge_result may improve performance. Create the index in base_proc so that it is available when select_proc is optimized.