存储过程详解
发表日期:2022-08-19 15:57:32 | 来源: | | 浏览(1253) 分类:SQLServer
存储过程就如同后端代码,能力非常强大,代码里无论逻辑是怎样的,最终也是把处理完的结果储存到数据库里。
然而存储过程你可以使用变量、虚拟表,循环,SQL支持的字符、日期、数学,聚合函数等,90%的后端代码都没什么复杂的逻辑,使得这些功能完全可以使用存储完成,也就是说把逻辑搬到了数据库里,代码就接参数-调存储-显示结果这么简单。
存储比代码的优点在于逻辑全在数据库,使得后端代码量、难度极大减少,项目重构方便,哪怕你是换语言只要库没变,存储全能用。而且数据处理使用存储会比代码快和方便,复杂的逻辑要执行大量SQL,代码一条一条执行会非常慢,尤其遇到递归,然而存储可以轻松解决,你只需要调用存储过程这一条SQL。
存储比代码的缺点在于逻辑全在数据库,使得新接手的程序员对项目了解起来很费劲,逻辑不易理解。而且写存储也对程序员数据库能力的要求过高。还有很大的一点是,依靠大量的存储过程执行复杂操作会拖慢数据库,往往一个存储过程执行数秒至数分钟。
现在的项目只要代码不烂到极点,往往性能的瓶颈都在数据库。所以尽量不要牺牲数据库性能换代码性能,因为代码想提高负载比数据库成本和难度低得多,手段也多。
言而总之,内部系统密集计算类的适合用存储过程,网站等高io的尽量代码计算+数据库->缓存/redis吧
一、存储过程的创建、参数格式
-- 如果没有参数 可以不写参数 CREATE PROCEDURE [存储名] @参数1 int, @参数2 varchar(50), @参数3 varchar(2000),@参数4 varchar(100) as -- 存储的主体 go
二、存储过程的调用方法
exec [存储过程名字] @参数1=1,@参数2='aaa', @参数3sql='bbbb',@参数4where ='ccccc'; 或者简写,即按字段顺序 exec [存储过程名字] 1,'aaa', 'bbbb','ccccc'; exec 也可以写成全称 execute
三、存储过程内执行SQL字符串
-- 参数可以传入SQL语句直接在存储过程里执行,通常不建议这样干! exec (@参数); -- 传入的参数也可以是半截sql,然后再拼起来执行,通常不建议这样干! -- 而且通常这么干都是在代码里把接收到的参数拼起来传,十有八九有SQL注入漏洞 exec ('delete from TestTab2 where a=b and d=c and '+@参数4where);
四、虚拟表/临时表用法及SQL联表写入/更新思路
做复杂业务时经常需要用到,临时表的好处就是在内存里速度快,存储过程执行完即销毁,只是临时创建使用。
意义在于可以把不同的实体表里的数据通过条件或计算拼凑到临时表里,达到自己想要的目标结果集
当然几乎所有临时表的场景你也可以不用,但是必然需要在代码里大量的循环去填充数据,效率肯定不如使用数据库字段关联填充数据效率高。
-- 定义临时表 DECLARE @table_tmp table ( a int, b VARCHAR(50), c int, d int, e VARCHAR(50), f VARCHAR(50), g DECIMAL DEFAULT 0 ); -- 写法用法和普通表没什么区别,考验你的SQL基础能力罢了 insert into @table_tmp (a, b, c, d) select uid,username,age,10 from Users where type=3; update @table_tmp set e=(select role_name from user_profile where uid = a) where age > 18; UPDATE t set t.f = r.role_name FROM @table_resoult as t, user_role as r where r.uid = t.a; update @table_tmp set g=(select sum(money) from user_account where uid = a) where g = 0; update c set c.d=b.score from @table_tmp c join ( select * from xxxxx ) b on c.a = b.uid and c.e = b.role; --最后达到你想要的结果集了,你可以把虚拟表的数据插入到目标真实表 insert into targetTab(a1,b1,c1,d1,e1,f1,g1) select a,b,c,d,e,f,g from @table_tmp; -- 或者存储过程直接返回临时表的结果 select * from @table_tmp;
五、变量
--可以定义变量 declare @var1 varchar(50) --给定义的变量赋值 select @username = username from users where UID = 1; --使用变量 update user_house set update_time=getdate(), username=@username where uid = 1;
六、条件判断 & 事务提交回滚 &
--开启事务 begin tran -- 这里进行业务操作 -- …… --如果有错 if (0 <> @@ERROR) begin --事务回滚 rollback tran; -- 返回错误码 select -1; end else begin --提交事务 commit tran; -- 可以返回修改行数或 其它内容 select @@ROWCOUNT; end
七、游标
游标是啥,通俗的将就是在SQL里实现while 循环
--定义变量 declare @uid int,@username varchar(50); -- 定义游标 填充数据 declare c1 cursor for select UID,UName from Users where uuid <> 0; --开启游标 open c1 aa:fetch next from c1 into @uid,@username -- 循环 while @@fetch_Status = 0 begin -- 业务逻辑 end -- 关闭游标 close c1 -- 销毁游标 deallocate c1