我与我的一位开发人员就构建TSQL存储过程的哲学进行了一般性讨论。
让我们做一些假设(以避免“不要在SP中放置业务逻辑”等行的响应):
基本上,我的同事已经在SQL Server的嵌套插件的SQL Server墙上砸了他的头。您可以将它们嵌套在一个级别之外。
即。 :
PROC C由PROC B调用 结果被插入到 临时表#X和操作是 执行然后结果集 返回
PROC B由PROC A调用 结果(我们原来的最终选择 来自PROC C + Transformations) 将其插入临时表#Z并执行操作,然后返回结果集
这会导致SQL Server抛出错误,指出您无法将插入嵌套到临时表中。
我同意这个逻辑,假设我们的四个原始前提,那么只允许将PROC C中执行的逻辑直接包含在PROC B中。
然而,我的同事觉得,作为一个优秀的面向对象的封装器,通过封装最终的嵌套插入代码,代码更易于维护。
另一方面,我认为将代码封装到使用临时表的CRUD操作中,从根本上反对SQL和关系数据库中固有的数据管理的声明性和过程性方法。最终,他的论点是如果逻辑只是在一个SP中,那么如果表模式发生变化,那么寻址表的所有SP都必须改变。这是一个有效的观点,但我觉得这不太可能,因为一旦我们的开发工作已经下台,就不会受到临时变更的影响。
我的论点是,通过封装临时表插入,用于第n级嵌套(如果可能 - 谢天谢地),将导致所有SP调用封装过程的情况(或者我们现在应该如果集中式封装过程发生变化,则无论如何都要将其称为方法?),因为除非输出相同,否则很可能导致调用父SP中断。
我想我的最终问题是,从根本上讲,T-SQL是声明性的,程序性的或命令性的语言。在我看来,它显然是一种混合物 - >我想如果我必须创建我会说的食谱:
10%声明(原则上是声明性的) 70%程序(在我们的例子中,业务流程在procs中的情况) 20%势在必行(存在势在必行的构造 - 尤其是在较新的SQL Server版本中)
P.S。目前他建议在SP调用中使用OUTPUT参数,而不是:
插入#temp exec spInsertUpdateTable
我对OUTPUT参数完全不喜欢,但我想这可能不得不飞。还有其他建议吗?
答案 0 :(得分:2)
不是答案,只是一些不在我头脑中的想法:
通过OUTPUT参数比通过结果集更有效地传递单值。但是,当返回值的数量增加时,其值会减小。
在SQL 2008中,您可以将临时表作为参数传递。好吧,为了实现这一点,你需要做很多设置,但即便如此,这也是值得的,因为你可以获得N级嵌套调用。
易于维护的代码是我们都应该努力的圣杯,因为 - 如果有任何正义 - 支持代码的人应该是其原始创建者。 [在这里插入Frankenstien博士的笑话。]这应该强调模块化代码的好处(“子程序”);如果您只需修改一个嵌套过程,并且不必更改输入或输出,那么您不必担心(即重构)有关调用或被其调用的过程。
至于陈述性与程序性与强制性,对不起,自从大学毕业以来已经好几年了,而且我已经在战壕中待了太长时间,无法在没有谷歌工作一小时的情况下讨论高调的理论。
答案 1 :(得分:1)
我想也许这可以避免回答问题,但我要做的第一件事是检查为什么所有这些临时表都需要传递。通常,构造良好的select,insert或update语句可以替换大量的临时表。这实际上是T-SQL的目的 - 能够编写单个语句来处理整个集合。所以,在你说“+转换”的地方,我直接说“啊,通过选择做转换,从解决方案中重构那些临时表。”有意义吗?
示例:查看是否可以使用两个嵌套视图而不是存储过程生成所需结果。没有问题在视图之间传递结果(这有点用词不当)加上你在整个操作中获得查询优化(SQL Server将扩展视图defs并立即优化整个事物)
答案 2 :(得分:1)
如果您仍在使用SQL Server 2000,我建议您阅读以下知识库文章: http://support.microsoft.com/kb/243586/
科: “由于某些临时表操作而重新编译 在存储过程中使用临时表可能导致每次执行过程时都重新编译存储过程。
要避免这种情况,请更改存储过程以使其满足以下要求: 包含临时表名称的所有语句都是指在同一存储过程中创建的临时表,而不是在调用或调用的存储过程中,或者在使用EXECUTE语句或sp_executesql存储过程执行的字符串中。“
我在负载下的生产系统中碰到了这个问题,这引起了一些重大的性能问题。