Analysis of the strange image of the temporary table with the same name in the nested stored procedure of SQL Server

In SQL Server's nested stored procedures, can there be local temporary tables with the same name in the outer stored procedures and the inner stored procedures (stored procedures that are called by nesting)? If so, are there any problems or restrictions? In the nested stored procedure, is it the temporary table of the outer stored procedure or the temporary table defined by oneself? Is there a "scope" scope for local temporary tables, similar to variables in high-level languages?

Note: It can also be called the parent stored procedure and the child stored procedure, the outer stored procedure and the inner stored procedure. These are just different titles or names. Here we uniformly use outer stored procedures and inner stored procedures. I won’t talk about it in the follow-up article.

Let's first look at an example, as shown below, we construct a simple example.

IF EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID(N'dbo.PRC_TEST') AND OBJECTPROPERTY(object_id, 'IsProcedure') =1)
BEGIN
DROP PROCEDURE dbo.PRC_TEST
END
GO
CREATE PROC dbo.PRC_TEST
AS
BEGIN

CREATE TABLE #tmp_test(id INT);

INSERT INTO #tmp_test
SELECT 1;

SELECT * FROM #tmp_test;

EXEC PRC_SUB_TEST

SELECT * FROM #tmp_test


END
GO

IF EXISTS(SELECT 1 FROM sys.objects WHERE object_id= OBJECT_ID(N'dbo.PRC_SUB_TEST' ) AND OBJECTPROPERTY(object_id, 'IsProcedure')=1)
BEGIN
DROP PROCEDURE dbo.PRC_SUB_TEST;
END
GO

CREATE PROCEDURE dbo.PRC_SUB_TEST
AS
BEGIN

CREATE TABLE #tmp_test(name VARCHAR(128));

INSERT INTO #tmp_test
SELECT name FROM sys.objects

SELECT * FROM #tmp_test;
END
GO

EXEC PRC_TEST;

The simple test seemed to be normal, and no problems were found. If you draw a conclusion at this time, it is too early! For example, if you see a swan is white, if you come to a conclusion: "All swans are white", in fact, there are black swans in this world, but you have never seen it! As shown below, we modify the stored procedure dbo.PRC_SUB_TEST, replace * with the field name name, as shown below:

IF EXISTS(SELECT 1 FROM sys.objects WHERE object_id= OBJECT_ID(N'dbo.PRC_SUB_TEST' ) AND OBJECTPROPERTY(object_id, 'IsProcedure')=1)
BEGIN
DROP PROCEDURE dbo.PRC_SUB_TEST;
END
GO

CREATE PROCEDURE dbo.PRC_SUB_TEST
AS
BEGIN

CREATE TABLE #tmp_test(name VARCHAR(128));

INSERT INTO #tmp_test
SELECT name FROM sys.objects

SELECT name FROM #tmp_test;
END
GO

Then repeat the above test, as shown below, if the stored procedure dbo.PRC_TEST is executed at this time, an error will be reported: "Invalid column name'name'."

At this point, as long as I execute the stored procedure dbo.PRC_SUB_TEST once, and then execute the stored procedure dbo.PRC_TEST, no error will be reported. And as long as you execute this stored procedure once, and then execute dbo.PRC_TEST in the current session or any other session, no error will be reported. Is it very confusing or confusing.

EXEC dbo.PRC_SUB_TEST;

EXEC PRC_TEST;

If you want to reproduce this phenomenon again, you can only reproduce this phenomenon through the following SQL or delete/rebuild stored procedures. It seems a little ghost phenomenon.

DBCC FREEPROCCACHE

Regarding this phenomenon, the official document (see the link address of the reference material for details) has such a description:

A local temporary table created within a stored procedure or trigger can have the same name as a temporary table that was created before the stored procedure or trigger is called. However, if a query references a temporary table and two temporary tables with the same name exist at that time, it is not defined which table the query is resolved against. Nested stored procedures can also create temporary tables with the same name as a temporary table that was created by the stored procedure that called it. However, for modifications to resolve to the table that was created in the nested procedure, the table must have the same structure, with the same column names, as the table created in the calling procedure. This is shown in the following example.

The name of the local temporary table created in the stored procedure or trigger can be the same as the name of the temporary table created before calling the stored procedure or trigger. However, if the query refers to a temporary table and there are two temporary tables with the same name at the same time, it does not define which table the query is parsed against. A nested stored procedure can also create a temporary table with the same name as the temporary table created by the stored procedure that calls it. However, in order to modify it to resolve to a table created in a nested procedure, this table must have the same structure and column names as the table created by the calling procedure. The following example illustrates this point.

CREATE PROCEDURE dbo.Test2
AS
CREATE TABLE #t(x INT PRIMARY KEY);
INSERT INTO #t VALUES (2);
SELECT Test2Col = x FROM #t;
GO

CREATE PROCEDURE dbo.Test1
AS
CREATE TABLE #t(x INT PRIMARY KEY);
INSERT INTO #t VALUES (1);
SELECT Test1Col = x FROM #t;
EXEC Test2;
GO

CREATE TABLE #t(x INT PRIMARY KEY);
INSERT INTO #t VALUES (99);
GO

EXEC Test1;
GO

In the official document, "There are two temporary tables with the same name at the same time, then it is not defined which table to parse the query against" the explanation feels a bit confusing. Here is a brief explanation, in the nested call of the stored procedure, it is allowed to have a local temporary table with the same name in the outer procedure and the inner stored procedure, but in the memory process, if you want to modify or parse it (modification is good Understand, such as adding indexes, adding fields and other DDL operations; for parsing, querying temporary tables, specifying field names in SQL, you need to resolve resolve), then this temporary table must have the same table structure at this time, otherwise an error will be reported. The official document tells you that it is not possible, but the specific reason is not stated. Then we might as well make some speculations, whether two local temporary tables are created in the nested call of the stored procedure? Is it possible that only one local temporary table is actually created? What about the reuse of local temporary tables? Then we simply verify, as shown below, here you can judge that two local temporary tables are actually created. There is no reuse of temporary tables.

SELECT *
FROM sys.dm_os_performance_counters
WHERE counter_name LIKE 'Temp Tables Creation Rate%';

EXEC PRC_TEST;

SELECT *
FROM sys.dm_os_performance_counters
WHERE counter_name LIKE 'Temp Tables Creation Rate%';

 

Of course, you can use the following SQL to verify, which is consistent with the results of the above verification.

IF EXISTS(SELECT 1 FROM sys.objects WHERE object_id= OBJECT_ID(N'dbo.PRC_SUB_TEST' ) AND OBJECTPROPERTY(object_id, 'IsProcedure')=1)
BEGIN
DROP PROCEDURE dbo.PRC_SUB_TEST;
END
GO


CREATE PROCEDURE dbo.PRC_SUB_TEST
AS
BEGIN

SELECT * FROM #tmp_test;

SELECT * FROM tempdb.dbo.sysobjects WHERE name LIKE '#tmp_test%'
CREATE TABLE #tmp_test(name VARCHAR(128));

INSERT INTO #tmp_test
SELECT name FROM sys.objects
SELECT * FROM tempdb.dbo.sysobjects WHERE name LIKE '#tmp_test%'
SELECT * FROM #tmp_test;
END
GO

Then let's take a look at the "scope" of the temporary table. I'm sorry I used such a concept. The official document does not have this concept. This is only one aspect of our thinking, and there is no need to lift up the details. As shown below, we modify the stored procedure

IF EXISTS(SELECT 1 FROM sys.objects WHERE object_id= OBJECT_ID(N'dbo.PRC_SUB_TEST' ) AND OBJECTPROPERTY(object_id, 'IsProcedure')=1)
BEGIN
DROP PROCEDURE dbo.PRC_SUB_TEST;
END
GO
CREATE PROCEDURE dbo.PRC_SUB_TEST
AS
BEGIN

SELECT * FROM #tmp_test;
CREATE TABLE #tmp_test(name VARCHAR(128));

INSERT INTO #tmp_test
SELECT name FROM sys.objects

SELECT * FROM #tmp_test;
END
GO

Through experimental verification, we found that the temporary table of the outer stored procedure is effective in the inner stored procedure. Its "scope" is before the temporary table of the same name in the inner stored procedure is created. This is the same as the global variables and local in the high-level language. Variable scope is a bit similar.

Since two local temporary tables have been created, why would an error be reported when modifying or parsing? A personal guess is that after the optimizer has parsed it, during the execution process, the database engine cannot judge it or there is no such logic in the code to control which temporary table is retrieved during the analysis or modification. It may be a defect in the code or some logical reason. The above is just a personal guess and reasoning. If there are any deficiencies or errors, please correct me.

Guess you like

Origin blog.csdn.net/hbznd/article/details/115247701