[推荐] 【T-MAC学习笔记18之--浅谈存储过程】 20feixianxxx]

发布时间:2016-12-6 16:15:51 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"[推荐] 【T-MAC学习笔记18之--浅谈存储过程】 20feixianxxx]",主要涉及到[推荐] 【T-MAC学习笔记18之--浅谈存储过程】 20feixianxxx]方面的内容,对于[推荐] 【T-MAC学习笔记18之--浅谈存储过程】 20feixianxxx]感兴趣的同学可以参考一下。

本帖最后由 feixianxxx 于 2009-11-27 21:36:29 编辑 这次讲得是 存储过程(proc) 存储过程分类: 1.用户自定义存储过程: 分成 TRANSACT-SQL存储过程和CLR存储过程 2.拓展存储过程(后续版本将删除这个,所以避免使用它了,用clr替代) 3.系统存储过程物理意义上讲,系统存储过程存储在源数据库中,并且带有 sp_ 前缀。 从逻辑意义上讲,系统存储过程出现在每个系统定义数据库和用户定义数据库的 sys 构架中。 存储过程的优点: 1.执行速度更快。 有两个原因:首先,在存储过程创建的时候,数据库已经对其进行了一次解析和优化。 其次,存储过程一旦执行,在内存中就会保留一份这个存储过程,这样下次再执行同样的存储过程时,可以从内存中直接调用 2.存储过程允许模块化程序设计。 当对数据库进行复杂操作时(如对多个表进行Update,Insert,Query,Delete 时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。 3.存储过程可以重复使用,可减少数据库开发人员的工作量 4.安全性高。 可设定只有某此用户才具有对指定存储过程的使用权。这里赋予的是对存储过程的权利,不是对存储过程里面的内部对象的权利 例;你要赋予PROC_s 的执行权利,但是不准用户user1有 PROC_S里面的k表的权限   exec deny select on k to user1  exec grant execute on PROC_S to user1 5.减少网络通信量。 调用一个行数不多的存储过程与直接调用SQL 语句的网络通信量可能不会有很大的差别, 可是如果存储过程包含上百行SQL 语句,那么其性能绝对比一条一条的调用SQL 语句要高得多。 6.布式工作. 应用程序和数据库的编码工作可以分别独立进行,而不会相互压制。 存储过程的规则:(更多参考MSDN) 1.不要在主体重包含一些DML语句,比如 create(alter ) default,function,view,trigger ,SET SHOWPLAN_XML等等 2.其他数据库对象均可在存储过程中创建。 可以引用在同一存储过程中创建的对象,只要引用时已经创建了该对象即可。 3.可以在存储过程内引用临时表。 4.存储过程中的参数的最大数目为 2100。 5.根据可用内存的不同,存储过程最大可达 128 MB。 6.数据库引擎将保存 SET QUOTED_IDENTIFIER 和 SET ANSI_NULLS 的设置。在存储过程中出现的 SET QUOTED_IDENTIFIER 和 SET ANSI_NULLS 语句不影响存储过程的功能。 存储过程的参数: 1.参数按方向分2种: in->传入内部; out->传入内部和传出外部 当用In类型的时候,参数一般用作条件供内部使用, 当用Out类型的时候,参数一般是用作返回值传给应用程序的,在定义时候用output指定. a.这里有个地方,当你的output参数传入后如果在proc内部进行了修改,它还是可以再次传出来的,不过值发生了变化,这个很像C等语言里面的参数地址传送。 b.proc本身也可以返回值 在它内部用return 指定返回值 然后用 DECLARE @result int;  EXECUTE @result = my_proc; 这种方式得到这个结果值 然后根据这个变量值 进行后续操作......(实际情况实际处理) 2.关于参数的赋值  example: CREATE PROCEDURE dbo.my_proc     @first int = NULL,  -- NULL default value     @second int = 2,    -- Default value of 2     @third int = 3      -- Default value of 3 AS SELECT @first, @second, @third; GO --这里执行的方式很多 EXECUTE dbo.my_proc; --结果/*NULL  2  3*/ EXECUTE dbo.my_proc 10, 20, 30;--结果/*10  20  30*/ EXECUTE dbo.my_proc @second = 500;--结果/*NULL  500  3*/ EXECUTE dbo.my_proc 40, @third = 30;--结果/*40  2  30*/ EXECUTE dbo.my_proc 40,default,50;--结果/*40  2  50*/ 执行存储过程 1.执行带有OUTPUT参数的PROC的时候 注意执行时候 对应的参数后面加上 output 2.执行一个不带架构名的PROC的时候 sql会自动按下面的顺序解析一个PROC 例:你连接在SALES 数据库 默认架构为sale 你的存储过程名为 p_s a.在SALES数据库的SYS架构下寻找p_s 找不到转到下面一步 b.继续在默认架构下寻找 这里是在sale架构下寻找p_s.如果它位于另外一个存储过程(sSALES.sale2.poc2)内部 则在sale2下寻找p_s。没找到 转到下面一步 c.在dbo架构下寻找p_s..- -||找不到 就弹错了... 3.这里还有一个技巧,在某些场合也许有用:你需要一个全局临时表来存储一些全局变量,这样就需要在每次SQL启动时候创建这么一个全局临时表 做法: --a.在MASTER库中创建: create proc sp_quanju  as create table #quanju (val sql_variant) --b.将这个存储过程设置成自动启动 exec sp_procoption 'sp_quanju','StartUp','TRUE'--要关掉只要把最后一个参数设置为FALSE 或者NO 查看存储过程:(详见MSDN) 这里就写几个系统存储过程或者目录视图 1.查询存储过程定义; sys.sql_modules ; OBJECT_DEFINITION(); sp_helptext 2.查询存储过程相关信息 sys.objects sys.procedures sp_help 误写系统存储过程那点事:   用户在MASTER数据库中创建以sp_开头的存储过程会有意外(in book) USE master; GO CREATE PROC dbo.sp_Proc1 AS PRINT 'master.dbo.sp_Proc1 executing in ' + DB_NAME(); EXEC('SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = ''BASE TABLE'';'); SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'; GO ---这里切换到另外一个数据库 USE Northwind; EXEC dbo.sp_Proc1; --最后DB_NAME()返回的是Northwind 动态查询返回的Northwind的表 而不是MASTER库 ,静态返回的确实MASTER的表 --这个存储过程里也没有明显切换数据库的语句 自动转化 ---这个时候我去姜它变成真正的系统存储过程--- USE master; EXEC sp_MS_marksystemobject 'dbo.sp_Proc1'; GO --接着去执行检验 发现都是在切换后的数据库下 USE Northwind; EXEC dbo.sp_Proc1; USE pubs; EXEC dbo.sp_Proc1; --如果我们在Northwind创建了一个相同名字的存储过程 就是和系统PROC一样的 怎么办?SQL是会调用用户定义的 USE Northwind; GO IF OBJECT_ID('dbo.sp_Proc1') IS NOT NULL   DROP PROC dbo.sp_Proc1; GO CREATE PROC dbo.sp_Proc1 AS PRINT 'Northwind.dbo.sp_Proc1 executing in ' + DB_NAME(); GO    --更加神奇的地方是 如果你在master用sp_开头建立的表 USE master; GO IF OBJECT_ID('dbo.sp_Globals') IS NOT NULL   DROP TABLE dbo.sp_Globals; GO CREATE TABLE dbo.sp_Globals (   var_name sysname     NOT NULL PRIMARY KEY,   val      SQL_VARIANT NULL ); USE Northwind; INSERT INTO dbo.sp_Globals(var_name, val)   VALUES('var1', 10); USE pubs; INSERT INTO dbo.sp_Globals(var_name, val)   VALUES('var2', CAST(1 AS BIT)); USE tempdb; SELECT var_name, val FROM dbo.sp_Globals; GO /* var_name     val                         ------------ ---------- var1           10 var2            1  */   ----上面的实例告诉我们不要在MASTER里面随便建立以SP_开头的对象

本帖最后由 feixianxxx 于 2009-11-28 21:44:32 编辑

做上 SF

18了吧

学习 t-mac

hao

.

学习

SS

学习

小麦 我不得不说你了 一个斑竹发20分的技术帖 

可以

bucuo

UP

学习一下拉

引用 1 楼 feixianxxx 的回复:关于延迟名称解析和编译的那点事 1.创建完PROC后 首先SQL会分析代码 检查它的语法错误.如果错误,直接创建失败.成功,转入下一步 2.然后尝试检查对象. 这里是关键点: 如果检查中的对象存在 就完整的执行 ,这个时候情感文章他就要去检查其中的列是否存在 一旦不存在对于的列,就产生错误;如果对象都不存在,它就会创建成功,把解析过程放到你下一次执行这个PROC的时候.   --上面哪个延迟的行为就叫延迟名称解析 SQL codeUSE tempdb;GOIFOBJECT_ID('dbo.usp_Proc1')ISNOTNULLDROPPROC dbo.usp_Proc1;GOIFOBJECT_ID('dbo.usp_Proc2')ISNOTNULLDROPPROC dbo.usp_Proc2;GOIFOBJECT_ID('dbo.T1')ISNOTNULLDROPTABLE dbo.T1;GOCREATEPROC dbo.usp_Proc1ASSELECT col1FROM dbo.T1;GO/*创建存储过程成功,这里就是延迟名称解析*/-- 执行失败EXEC dbo.usp_Proc1;/*         错误 对象不存在*/--建立表T1CREATETABLE dbo.T1(col1INT);INSERTINTO dbo.T1(col1)VALUES(1);GOEXEC dbo.usp_Proc1;GO/*col1         -----------         1*/CREATEPROC dbo.usp_Proc2ASSELECT col2FROM dbo.T1;GO/*直接建立proc2失败,因为在T1存在的前提下 它不存在COL2*/ 关于重用执行计划和重新编译 一般一个存储过程成功执行了一次后,SQL将保存执行计划.然后又是一般情况下 它就一直重用这个执行计划 不管它是不是合适 - -| SQL code举个例子:CREATEPROC [email protected] OrderID, CustomerID, EmployeeID, OrderDateFROM dbo.OrdersWHERE OrderDate>[email protected];GOEXEC dbo.usp_GetOrders'19980506';EXEC dbo.usp_GetOrders'19960101';--这个Orders表有880条大于19960101的记录 但是只有2条大于19980506--第一个存储过程执行后 产生了一个高选择性的执行计划,第二个查询虽然更加适合全表扫描,但是它用的还是第一个执行后的执行计划 浪费很大 这个可以去看执行计划ALTERPROC [email protected] RECOMPILE----------可以使用WITH RECOMPILE 选项强制每次执行存储过程就重新编译ASSELECT OrderID, CustomerID, EmployeeID, OrderDateFROM dbo.OrdersWHERE OrderDate>[email protected];GO ---至于自动造成重新编译的情况有如下: 1.基对象发生架构更改的时候(增晒列,索引删除建立),更改set选项等 2.更改了被引用对象的大量数据 3.长久不是用执行计划 关于存储过程中的变量 如果你在存储过程中定义变量 它也会闹出点事情来.因为优化器无法知道里面那个变量的内容,所以它会使用一个保守的硬编码值,它约是行数的30% 太抽象 看例子 SQL codeCREATEPROC [email protected][email protected];[email protected]=DATEADD(day,[email protected],CONVERT(VARCHAR(8),GETDATE(),112));SELECT OrderID, CustomerID, EmployeeID, OrderDateFROM dbo.OrdersWHERE OrderDate>[email protected];[email protected] [email protected]们执行这个存储过程 EXEC dbo.usp_GetOrders; [email protected]=0 输出一条记录 (假设有10000条)[email protected] 的变量它不认识 所以它估计返回行数应该是总行数的30% 就是3000条 它就选择低选择性估计 用了表扫描--实际上这个搜索时高效的 应该用聚集的索引....[email protected] [email protected]=0ASSELECT OrderID, CustomerID, EmployeeID, OrderDateFROM dbo.OrdersWHERE OrderDate>=DATEADD(day,[email protected],CONVERT(VARCHAR(8),GETDATE(),112));GO2.再写一个存储过程处理CREATEPROC [email protected] OrderID, CustomerID, EmployeeID, OrderDateFROM dbo.OrdersWHERE OrderDate>[email protected];GO--修改 usp_GetOrdersALTERPROC [email protected][email protected];[email protected]=DATEADD(day,[email protected],CONVERT(VARCHAR(8),GETDATE(),112));--调用 dbo.usp_GetOrdersQueryEXEC [email protected];3.使用2005新东西 OPTIMIZEFORALTERPROC [email protected][email protected];[email protected]=DATEADD(day,[email protected],CONVERT(VARCHAR(8),GETDATE(),112));SELECT OrderID, CustomerID, EmployeeID, OrderDateFROM dbo.OrdersWHERE OrderDate>[email protected](OPTIMIZEFOR(@odate='99991231'));--这里 OPTIMIZE FOR 提供一个参考值 加入你知[/code] 比较实用

额外让我而非我

受教了~多谢!

忒牛的 

dssadddasadassassas

学习了

看看

学习了哦

好东西 

关于重编译是不是应该顺便把语句级的重编译写上,那个应该更实用。

学习了

WSADATA WSAData; SOCKET sock; SOCKADDR_IN addr_in; IP_HEADER   ipHeader; PSD_HEADER  psdHeader;          TCP_HEADER  tcpHeader; char szSendBuf[60] = {0}; BOOL flag = true; int rect,nTimeOver; if(WSAStartup(MAKEWORD(2,2), &WSAData)!=0) { AfxMessageBox("WSAStartup Error! \n"); // return false; } if((sock = WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,    WSA_FLAG_OVERLAPPED))== INVALID_SOCKET) { AfxMessageBox("Socket Setup Error!\n"); // return false; } if(setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char *)&flag,sizeof(flag) )==SOCKET_ERROR) { AfxMessageBox("setsocket IP_HDRINCL ERROR!\n"); // return false; } nTimeOver=1000;         if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver, sizeof(nTimeOver))==SOCKET_ERROR)          { AfxMessageBox("setsockopt SO_SNDTIMEO error!\n"); } addr_in.sin_family = AF_INET; CString Pstr,IPstr; GetDlgItem(IDC_EDIT2)->GetWindowText(Pstr); GetDlgItem(IDC_EDIT1)->GetWindowText(IPstr); addr_in.sin_port = htons(atoi(Pstr));         addr_in.sin_addr.S_un.S_addr = inet_addr(IPstr); //填充IP首部 ipHeader.h_lenver =((4<<4)|(sizeof(ipHeader)/sizeof(unsigned long)));         ipHeader.tos = 0; ipHeader.total_len = htons(sizeof(ipHeader)+sizeof(tcpHeader)); ipHeader.ident = 1; ipHeader.frag_offset = 0; ipHeader.TTL = 128; ipHeader.proto = IPPROTO_TCP; ipHeader.checksum = 0; ipHeader.sourceIp = inet_addr("10.70.146.58"); ipHeader.destIp = inet_addr(IPstr); //填充TCP首部 tcpHeader.sport = htons(SOURCE_PORT); int dport; dport = sscanf((char*)(LPCSTR)Pstr, "%d", &dport); tcpHeader.dport = htons(dport); tcpHeader.th_sep = htons(0x12345678); tcpHeader.ack_serial_number = 0; tcpHeader.len_save_frag = (sizeof(tcpHeader)/4<<4|0); tcpHeader.frag = 2; ////修改这里来实现不同的标志位探测,2是SYN,1是FIN,16是ACK探测 等等     tcpHeader.checksum = 0; tcpHeader.uragent_p = 0; tcpHeader.windows_size = htons(512); //填充tcp伪头部 psdHeader.daddr = inet_addr(IPstr); psdHeader.saddr = inet_addr("10.70.146.58"); psdHeader.mbz = 0; psdHeader.tcpl = htons(sizeof(tcpHeader)); psdHeader.ptcl = IPPROTO_TCP; ///计算校验和 memcpy(szSendBuf,&psdHeader,sizeof(psdHeader)); memcpy(szSendBuf+sizeof(psdHeader),&tcpHeader,sizeof(tcpHeader)); tcpHeader.checksum = Tcp_CheckSum((USHORT *)szSendBuf,sizeof(tcpHeader)+sizeof(psdHeader)); memcpy(szSendBuf,&ipHeader,sizeof(ipHeader)); memcpy(szSendBuf+sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader));          memset(szSendBuf+sizeof(ipHeader)+sizeof(tcpHeader), 0, 4); ipHeader.checksum = Tcp_CheckSum((unsigned short *)szSendBuf,sizeof(ipHeader)+sizeof(tcpHeader));         memcpy(szSendBuf, &ipHeader, sizeof(ipHeader)); rect = sendto(sock,szSendBuf,sizeof(ipHeader)+sizeof(tcpHeader),0,(struct sockaddr*)&addr_in,sizeof(SOCKADDR_IN));         if(rect == SOCKET_ERROR) { SetTimer(1,3000,NULL); AfxMessageBox("send fail"); }         else { AfxMessageBox("send OK"); }         closesocket(sock);          WSACleanup();

非常好.

建议把里面在一些错别字改一下,还有 最后一句话 没写完?

好多,慢慢研究下

顶了,支持了

up

定案啊 

也就是,这样的了????

学习!

学习,

我分少,我学习!

xuexi 

学习

study...

学习下,呵呵

student

T mac 来顶偶像的贴

hehe

.....学习,收藏

学习

该回复于2009-11-28 18:58:07被版主删除

dddddddddddddddd

学习中

本帖最后由 feixianxxx 于 2009-11-28 21:39:37 编辑

什么..................

原来是打广告

引用 28 楼 herowang 的回复:建议把里面在一些错别字改一下,还有 最后一句话 没写完? 》。。。 马上改

关于存储过程的内容还是要好好的复习下的

学习加搜藏

收藏了 谢谢分享

收藏了   谢谢分享

收藏了   谢谢分享

sf

ding ding ding 

什么..................

什么..................

学习了

学习

看哈

学习 t-mac

xuexile,xiexie

来学习的

强烈支持楼主,虚心向楼主学习....

my god

asdasdasdasdasdasda

引用 10 楼 fredrickhu 的回复:小麦 我不得不说你了 一个斑竹发20分的技术帖建议发300分的

学习

sf

我是来赚分的!

大开发好卡 菲卡毒素发

学习,虽然不怎么看得懂

学习了。额呵呵

领教了

学习了,呵呵

good,学习

你也忒猛了吧

好厉害啊

好东西 顶一下! 

很不错啊

好贴,先收藏慢慢看

好贴。学习学习

学习了

Mark

该回复于2009-12-01 23:34:10被版主删除

该回复于2009-12-02 13:13:56被版主删除

请问T-MAC下 这个存储过程有什么意义没? 还有为什么要使用到存储过程? 我是真的不明白,希望你用简单的文字描述下 可以吗?  学习ing。

mark

快点撒的啊是否阿斯放量杀跌飞机拉萨发

例子很经典

引用 92 楼 allenping923 的回复:请问T-MAC下 这个存储过程有什么意义没? 还有为什么要使用到存储过程? 我是真的不明白,希望你用简单的文字描述下 可以吗?  学习ing。 参看存储过程优点 

学习了

学习

up

謝謝。

上一篇:查询两个表中日期最大的那个表中的数据 40byecisv]
下一篇:Sql Server2012 安装失败!求解释。 40xiang520jl]

相关文章

相关评论