成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

SQL Server的嵌套存儲(chǔ)過(guò)程中使用同名的臨時(shí)表怪像淺析

存儲(chǔ) 存儲(chǔ)軟件
SQL Server的嵌套存儲(chǔ)過(guò)程,外層存儲(chǔ)過(guò)程和內(nèi)層存儲(chǔ)過(guò)程(被嵌套調(diào)用的存儲(chǔ)過(guò)程)中可以存在相同名稱的本地臨時(shí)表嗎?如果可以的話,那么有沒(méi)有什么問(wèn)題或限制呢?

[[381365]]

本文轉(zhuǎn)載自微信公眾號(hào)「DBA閑思雜想錄」,作者瀟湘隱者 。轉(zhuǎn)載本文請(qǐng)聯(lián)系DBA閑思雜想錄公眾號(hào)。  

SQL Server的嵌套存儲(chǔ)過(guò)程,外層存儲(chǔ)過(guò)程和內(nèi)層存儲(chǔ)過(guò)程(被嵌套調(diào)用的存儲(chǔ)過(guò)程)中可以存在相同名稱的本地臨時(shí)表嗎?如果可以的話,那么有沒(méi)有什么問(wèn)題或限制呢?在嵌套存儲(chǔ)過(guò)程中,調(diào)用的是外層存儲(chǔ)過(guò)程的臨時(shí)表還是自己定義的臨時(shí)表呢?是否類似高級(jí)語(yǔ)言的變量一樣,本地臨時(shí)表有沒(méi)有“作用域“范圍呢?

注意:也可以稱呼為父存儲(chǔ)過(guò)程和子存儲(chǔ)過(guò)程,外層存儲(chǔ)過(guò)程和內(nèi)層存儲(chǔ)過(guò)程...。這些只是不同的稱呼或叫法而已。我們這里統(tǒng)一使用外層存儲(chǔ)過(guò)程和內(nèi)層存儲(chǔ)過(guò)程。后續(xù)文章部分不再述說(shuō)。

我們先來(lái)看一個(gè)例子,如下所示,我們構(gòu)造一個(gè)簡(jiǎn)單的例子。

  1. IF EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID(N'dbo.PRC_TEST'AND OBJECTPROPERTY(object_id, 'IsProcedure') =1) 
  2. BEGIN 
  3.  DROP PROCEDURE dbo.PRC_TEST 
  4. END 
  5. GO 
  6. CREATE PROC dbo.PRC_TEST 
  7. AS 
  8. BEGIN 
  9.  
  10.  CREATE TABLE #tmp_test(id INT); 
  11.  
  12.  INSERT INTO #tmp_test 
  13.  SELECT 1; 
  14.  
  15.  SELECT * FROM #tmp_test; 
  16.  
  17.  EXEC PRC_SUB_TEST 
  18.  
  19.  SELECT * FROM #tmp_test 
  20.   
  21.  
  22. END 
  23. GO 
  24.  
  25.  
  26.  
  27. IF EXISTS(SELECT 1 FROM sys.objects WHERE object_id= OBJECT_ID(N'dbo.PRC_SUB_TEST' ) AND OBJECTPROPERTY(object_id, 'IsProcedure')=1) 
  28. BEGIN 
  29.  DROP PROCEDURE dbo.PRC_SUB_TEST; 
  30. END 
  31. GO 
  32.  
  33.  
  34. CREATE PROCEDURE dbo.PRC_SUB_TEST 
  35. AS 
  36. BEGIN 
  37.      
  38.  CREATE TABLE #tmp_test(name VARCHAR(128)); 
  39.  
  40.  INSERT INTO #tmp_test 
  41.  SELECT name FROM sys.objects 
  42.  
  43.  SELECT * FROM #tmp_test; 
  44. END 
  45. GO 
  46.  
  47.  
  48. EXEC PRC_TEST; 

 

簡(jiǎn)單測(cè)試似乎正常,并沒(méi)有發(fā)現(xiàn)什么問(wèn)題。如果此時(shí)你就下一個(gè)結(jié)論的話,那么就為時(shí)過(guò)早了!打個(gè)比方,你看見(jiàn)一只天鵝是白色的,如果你下了一個(gè)定論:“所有天鵝都是白色的”,其實(shí)這個(gè)世界真的有黑天鵝,只是你沒(méi)有見(jiàn)過(guò)而已!如下所示,我們修改一下存儲(chǔ)過(guò)程dbo.PRC_SUB_TEST,使用字段名name替換*,如下所示:

  1. IF EXISTS(SELECT 1 FROM sys.objects WHERE object_id= OBJECT_ID(N'dbo.PRC_SUB_TEST' ) AND OBJECTPROPERTY(object_id, 'IsProcedure')=1) 
  2. BEGIN 
  3.  DROP PROCEDURE dbo.PRC_SUB_TEST; 
  4. END 
  5. GO 
  6.  
  7. CREATE PROCEDURE dbo.PRC_SUB_TEST 
  8. AS 
  9. BEGIN 
  10.      
  11.  CREATE TABLE #tmp_test(name VARCHAR(128)); 
  12.  
  13.  INSERT INTO #tmp_test 
  14.  SELECT name FROM sys.objects 
  15.  
  16.  SELECT name FROM #tmp_test; 
  17. END 
  18. GO 

然后重復(fù)上面測(cè)試,如下所示,此時(shí)執(zhí)行存儲(chǔ)過(guò)程dbo.PRC_TEST的話,就會(huì)報(bào)錯(cuò):“Invalid column name 'name'.”

 

此時(shí)只要先我執(zhí)行一次存儲(chǔ)過(guò)程dbo.PRC_SUB_TEST,然后再去執(zhí)行存儲(chǔ)過(guò)程dbo.PRC_TEST就不會(huì)報(bào)錯(cuò)了。而且只要執(zhí)行過(guò)一次這個(gè)存儲(chǔ)過(guò)程,然后在當(dāng)前會(huì)話或其它任何會(huì)話執(zhí)行dbo.PRC_TEST都不會(huì)報(bào)錯(cuò)了。是否非常讓人迷惑或不解。

  1. EXEC dbo.PRC_SUB_TEST; 
  2. EXEC PRC_TEST; 

如果你要再次重現(xiàn)這個(gè)現(xiàn)象的話,只能通過(guò)下面SQL或者刪除/重建存儲(chǔ)過(guò)程的方式,才能重現(xiàn)這個(gè)現(xiàn)象。似乎有點(diǎn)幽靈現(xiàn)象的感覺(jué)。

  1. DBCC FREEPROCCACHE 

關(guān)于這個(gè)現(xiàn)象,官方文檔(詳見(jiàn)參考資料的鏈接地址)有這么一段描述:

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.

在存儲(chǔ)過(guò)程或觸發(fā)器中創(chuàng)建的本地臨時(shí)表的名稱可以與在調(diào)用存儲(chǔ)過(guò)程或觸發(fā)器之前創(chuàng)建的臨時(shí)表名稱相同。但是,如果查詢引用臨時(shí)表,而同時(shí)有兩個(gè)同名的臨時(shí)表,則不定義針對(duì)哪個(gè)表解析該查詢。嵌套存儲(chǔ)過(guò)程同樣可以創(chuàng)建與調(diào)用它的存儲(chǔ)過(guò)程所創(chuàng)建的臨時(shí)表同名的臨時(shí)表。但是,為了對(duì)其進(jìn)行修改以解析為在嵌套過(guò)程中創(chuàng)建的表,此表必須與調(diào)用過(guò)程創(chuàng)建的表具有相同的結(jié)構(gòu)和列名。下面的示例說(shuō)明了這一點(diǎn)。

  1. CREATE PROCEDURE dbo.Test2 
  2. AS 
  3.     CREATE TABLE #t(x INT PRIMARY KEY); 
  4.     INSERT INTO #t VALUES (2); 
  5.     SELECT Test2Col = x FROM #t; 
  6. GO 
  7.  
  8. CREATE PROCEDURE dbo.Test1 
  9. AS 
  10.     CREATE TABLE #t(x INT PRIMARY KEY); 
  11.     INSERT INTO #t VALUES (1); 
  12.     SELECT Test1Col = x FROM #t; 
  13. EXEC Test2; 
  14. GO 
  15.  
  16. CREATE TABLE #t(x INT PRIMARY KEY); 
  17. INSERT INTO #t VALUES (99); 
  18. GO 
  19.  
  20. EXEC Test1; 
  21. GO 

官方文檔中“同時(shí)有兩個(gè)同名的臨時(shí)表,則不定義針對(duì)哪個(gè)表解析該查詢”這種闡述感覺(jué)還是讓人有點(diǎn)迷糊。這里簡(jiǎn)單解釋一下,在存儲(chǔ)過(guò)程的嵌套調(diào)用中,允許外層過(guò)程和內(nèi)層存儲(chǔ)過(guò)程中存在相同名字的本地臨時(shí)表,但是在內(nèi)存過(guò)程中,如果要對(duì)其進(jìn)行修改或解析(修改很好理解,例如新增索引,增加字段等這類DDL操作;關(guān)于解析,查詢臨時(shí)表,SQL中指定字段名,就需要解析resolve),那么此時(shí)這個(gè)臨時(shí)表必須表結(jié)構(gòu)一致,否則就會(huì)報(bào)錯(cuò)。官方文檔,就是這么一句話,告訴你不行,但是具體原因沒(méi)有說(shuō)。那么我們不妨做一些推測(cè),在存儲(chǔ)過(guò)程的嵌套調(diào)用中,是否創(chuàng)建了兩個(gè)本地臨時(shí)表呢?有沒(méi)有可能實(shí)際只創(chuàng)建了一個(gè)本地臨時(shí)表呢?出現(xiàn)本地臨時(shí)表重用的情況呢?那么我們簡(jiǎn)單驗(yàn)證一下,如下所示,這里可以判斷實(shí)際上創(chuàng)建了兩個(gè)本地臨時(shí)表。并沒(méi)有出現(xiàn)臨時(shí)表重用的情況。

  1. SELECT *  
  2. FROM sys.dm_os_performance_counters 
  3. WHERE counter_name LIKE 'Temp Tables Creation Rate%'
  4.  
  5. EXEC PRC_TEST; 
  6.  
  7. SELECT *  
  8. FROM sys.dm_os_performance_counters 
  9. WHERE counter_name LIKE 'Temp Tables Creation Rate%'

 

當(dāng)然你可以用下面SQL來(lái)進(jìn)行驗(yàn)證,跟上面驗(yàn)證的結(jié)果一致。

  1. IF EXISTS(SELECT 1 FROM sys.objects WHERE object_id= OBJECT_ID(N'dbo.PRC_SUB_TEST' ) AND OBJECTPROPERTY(object_id, 'IsProcedure')=1) 
  2. BEGIN 
  3.  DROP PROCEDURE dbo.PRC_SUB_TEST; 
  4. END 
  5. GO 
  6.  
  7.  
  8. CREATE PROCEDURE dbo.PRC_SUB_TEST 
  9. AS 
  10. BEGIN 
  11.      
  12.  SELECT * FROM #tmp_test; 
  13.  
  14.  SELECT *  FROM tempdb.dbo.sysobjects WHERE name LIKE '#tmp_test%' 
  15.  CREATE TABLE #tmp_test(name VARCHAR(128)); 
  16.  
  17.  INSERT INTO #tmp_test 
  18.  SELECT name FROM sys.objects 
  19.  SELECT *  FROM tempdb.dbo.sysobjects WHERE name LIKE '#tmp_test%' 
  20.  SELECT * FROM #tmp_test; 
  21. END 
  22. GO 

然后我們來(lái)看看臨時(shí)表的“作用域”,抱歉我用這么一個(gè)概念,官方文檔是沒(méi)有這個(gè)概念,這個(gè)只是我們思考的一個(gè)方面,細(xì)節(jié)方面沒(méi)有必要抬杠。如下所示,我們修改一下存儲(chǔ)過(guò)程

  1. IF EXISTS(SELECT 1 FROM sys.objects WHERE object_id= OBJECT_ID(N'dbo.PRC_SUB_TEST' ) AND OBJECTPROPERTY(object_id, 'IsProcedure')=1) 
  2. BEGIN 
  3.  DROP PROCEDURE dbo.PRC_SUB_TEST; 
  4. END 
  5. GO 
  6. CREATE PROCEDURE dbo.PRC_SUB_TEST 
  7. AS 
  8. BEGIN 
  9.      
  10.  SELECT * FROM #tmp_test; 
  11.  CREATE TABLE #tmp_test(name VARCHAR(128)); 
  12.  
  13.  INSERT INTO #tmp_test 
  14.  SELECT name FROM sys.objects 
  15.  
  16.  SELECT * FROM #tmp_test; 
  17. END 
  18. GO 

通過(guò)實(shí)驗(yàn)驗(yàn)證,我們發(fā)現(xiàn)外層存儲(chǔ)過(guò)程的臨時(shí)表在內(nèi)層存儲(chǔ)過(guò)程中有效,它的“作用域”是在內(nèi)層存儲(chǔ)過(guò)程的同名臨時(shí)表創(chuàng)建之前, 這個(gè)跟高級(jí)語(yǔ)言中的全局變量和局部變量作用域有點(diǎn)類似。

 

既然創(chuàng)建了兩個(gè)本地臨時(shí)表,那么為什么修改或解析的時(shí)候就會(huì)報(bào)錯(cuò)呢?個(gè)人的一個(gè)猜測(cè)是,優(yōu)化器解析過(guò)后,在執(zhí)行過(guò)程中,解析或修改的時(shí)候,數(shù)據(jù)庫(kù)引擎無(wú)法判斷或者代碼里面沒(méi)有這種邏輯去控制檢索哪一個(gè)臨時(shí)表。有可能是代碼里面的一個(gè)缺陷亦或是某種邏輯原因?qū)е隆I鲜鰞H僅是個(gè)人的一個(gè)猜測(cè)、推理。如有不足或不對(duì)的地方,敬請(qǐng)指正。

參考資料:

https://docs.microsoft.com/zh-cn/previous-versions/sql/sql-server-2012/ms174979(v=sql.110)?redirectedfrom=MSDN

責(zé)任編輯:武曉燕 來(lái)源: DBA閑思雜想錄
相關(guān)推薦

2010-11-12 13:27:13

動(dòng)態(tài)sql

2010-11-12 09:18:13

SQL Server存

2011-08-15 15:56:31

SQL Server

2010-07-22 15:56:04

SQL Server臨

2011-09-01 13:09:58

SQL Server DataTable作為

2010-10-19 14:45:01

SQL SERVER臨

2010-10-09 16:41:54

MYSQL存儲(chǔ)過(guò)程

2009-09-14 16:29:39

LINQ嵌套

2010-07-15 12:38:14

SQL Server存

2021-01-18 05:23:14

SQL 排序Server

2009-08-04 10:29:06

在C#中使用存儲(chǔ)過(guò)程

2010-07-08 14:42:34

SQL Server臨

2010-10-19 15:25:05

Sql Server臨

2010-09-14 10:16:57

sql server

2011-03-24 13:38:47

SQL Server 存儲(chǔ)分頁(yè)

2010-09-16 15:10:48

SQL Server表

2009-07-01 02:29:24

臨時(shí)表T-SQL

2010-09-16 16:23:06

sql server批

2011-03-29 13:22:07

SQL Server臨時(shí)表表變量

2010-09-16 15:03:10

SQL Server臨
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 欧美日韩精品一区二区三区四区 | 91视视频在线观看入口直接观看 | 国产美女在线看 | 密室大逃脱第六季大神版在线观看 | 欧美性大战xxxxx久久久 | www.887色视频免费 | 欧美一区二区二区 | 国产视频三区 | 久久五月婷 | 2018国产大陆天天弄 | 日韩精品在线一区 | 天天躁日日躁狠狠躁2018小说 | 中文字幕精品一区 | 精品国产一区二区三区久久影院 | 日韩精品免费视频 | 成人国产精品免费观看 | 亚洲欧美日韩一区二区 | 久久99精品久久久久久 | 久久视频精品 | 久久亚洲综合 | 一区二区免费在线视频 | 97日韩精品| 欧美亚洲国语精品一区二区 | 激情久久网 | 国产精品高清一区二区三区 | 国产日韩一区二区三免费 | 丝袜美腿一区二区三区动态图 | 欧美成人h版在线观看 | 中文字幕国产高清 | 国产精品网址 | av日韩高清 | 91精品国产综合久久久动漫日韩 | 精品一区二区电影 | 天天操网 | 国产一区二区三区高清 | 精品久久久一区二区 | 亚洲黄色成人网 | 久久久免费电影 | 日本欧美在线 | 国产精品久久久久久吹潮 | 国产激情视频在线观看 |