debugsqlMinor
Estimated plan generation succeeds for batch creating and using #temp table but fails with a permanent table
Viewed 0 times
failssucceedscreatingwithtempbutbatchplangenerationfor
Problem
In reviewing the estimated execution plan creation process, I came across this section in SQL Server Execution plans by Grant Fritchey, He mentions:
The optimizer, which is what generates estimated execution plans,
doesn't execute T-SQL. It does run the statements through the
algebrizer...that is responsible for
verifying the names of database objects. Since SQL Server has not yet
executed the query, the temporary table does not yet exist. This is
the cause of the error. Running this same bit of code through the
actual execution plan will work perfectly.
In the book he references this code:
and the Error you will receive is
Msg 208, Level 16, State 1, Line 7 Invalid object name 'TempTable'.
To me, this wasn't a temporary table but instead an actual table. So when I tried with a temporary "#" table. I found that the estimated execution plan generated without issue. The estimated plan that was generated is shown here.
Can someone explain why there is this difference? Shouldn't the #table not be generated?
Fritchey, G. (2012). SQL Server Execution Plans. Springfield, USA: Simple Talk Publishing.
The optimizer, which is what generates estimated execution plans,
doesn't execute T-SQL. It does run the statements through the
algebrizer...that is responsible for
verifying the names of database objects. Since SQL Server has not yet
executed the query, the temporary table does not yet exist. This is
the cause of the error. Running this same bit of code through the
actual execution plan will work perfectly.
In the book he references this code:
CREATE TABLE TempTable
(
Id INT IDENTITY(1, 1)
);
INSERT INTO TempTable
DEFAULT VALUES
SELECT *
FROM TempTable;and the Error you will receive is
Msg 208, Level 16, State 1, Line 7 Invalid object name 'TempTable'.
To me, this wasn't a temporary table but instead an actual table. So when I tried with a temporary "#" table. I found that the estimated execution plan generated without issue. The estimated plan that was generated is shown here.
Create table #temp
(
ID INT IDENTITY (1,1)
)
Insert into #temp
DEFAULT VALUES
SELECT *
FROM #tempCan someone explain why there is this difference? Shouldn't the #table not be generated?
Fritchey, G. (2012). SQL Server Execution Plans. Springfield, USA: Simple Talk Publishing.
Solution
In SQL Server 2000 the
Invalid object name '#temp'.
However since SQL Server 2005 compiling a plan with a local temporary table does actually create the temporary table behind the scenes.
You can see this by getting the estimated plan for
Which produces an output like
The negative object id is the id of the object fleetingly created. Polling
The estimated plan you see for the statements referencing the temp table is of limited use however as even the addition of a single row to the temp table will trigger a statement level recompile and potentially a different plan when you actually execute the SQL.
This behaviour does not apply to global temporary tables or permanent tables.
I presume this is also the same reason as
#temp table version does fail with the messageInvalid object name '#temp'.
However since SQL Server 2005 compiling a plan with a local temporary table does actually create the temporary table behind the scenes.
You can see this by getting the estimated plan for
Create table #temp
(
ID INT IDENTITY (1,1)
)
Insert into #temp
DEFAULT VALUES
SELECT *
FROM #temp
OPTION (RECOMPILE, QUERYTRACEON 8605, QUERYTRACEON 3604);
DROP TABLE #tempWhich produces an output like
The negative object id is the id of the object fleetingly created. Polling
tempdb.sys.tables in a loop whilst generating the estimated plan and comparing with the TableID subsequently output can show this.The estimated plan you see for the statements referencing the temp table is of limited use however as even the addition of a single row to the temp table will trigger a statement level recompile and potentially a different plan when you actually execute the SQL.
This behaviour does not apply to global temporary tables or permanent tables.
I presume this is also the same reason as
/*Works fine (assuming T doesn't exist)*/
IF 1 = 1
SELECT 1 AS X
INTO T
ELSE
SELECT 1 AS X
INTO T
/*Fails (There is already an object named '#T' in the database.)*/
IF 1 = 1
SELECT 1 AS X
INTO #T
ELSE
SELECT 1 AS X
INTO #TCode Snippets
Create table #temp
(
ID INT IDENTITY (1,1)
)
Insert into #temp
DEFAULT VALUES
SELECT *
FROM #temp
OPTION (RECOMPILE, QUERYTRACEON 8605, QUERYTRACEON 3604);
DROP TABLE #temp/*Works fine (assuming T doesn't exist)*/
IF 1 = 1
SELECT 1 AS X
INTO T
ELSE
SELECT 1 AS X
INTO T
/*Fails (There is already an object named '#T' in the database.)*/
IF 1 = 1
SELECT 1 AS X
INTO #T
ELSE
SELECT 1 AS X
INTO #TContext
StackExchange Database Administrators Q#153607, answer score: 4
Revisions (0)
No revisions yet.