什么时候应该使用存储过程?


19

如果我将所有业务逻辑都包含在代码中并使用Entity Framework,那么在什么情况下(如果有),将某些业务逻辑移至存储过程中而不是将其全部保留在代码中会更好吗?

需要明确的是,我的意思是与当前设置(代码中的业务逻辑)结合使用,而不是与其结合使用。我已经看到了许多类似的问题,这些问题都要求在存储过程中拥有所有业务逻辑的利弊,但是对于保留少量使用边缘过程逻辑的同时保留其余业务逻辑的情况,我没有发现太多的益处在代码中。

如果有所作为,我正在使用MSSQL和Entity Framework。


在以下情况下,我曾使用过存储过程:

  • 一份复杂的报告需要几分钟才能运行(这是Web应用程序中的页面)。我发现我可以编写比LINQ提供的SQL更有效的SQL(只需花费几秒钟即可运行)。
  • 一个Web应用程序需要读写一个单独数据库中的几个表,其中包含许多其他与该应用程序无关的敏感信息。我没有给它访问所有内容的权限,而是使用了一个存储过程,该过程仅执行所需的操作,并且仅返回有限的信息。然后,可以只给Web应用程序访问此存储过程的权限,而不能访问任何表等。

在问这个问题之前,我查看了其他帖子:


4
两种情况都是编写存储过程的完全合理的理由。您是在问为什么他们合法吗?
罗伯特·哈维

@RobertHarvey我正在确保它们是合法的,并在寻找其他情况或原因,为什么您可能会产生异常并编写存储过程,而不是将其保留在代码中。
艾米·巴雷特

当您确定存储过程比其他可用技术更好地解决了问题时,您将例外并编写一个存储过程,这正是您所做的。
罗伯特·哈维

Answers:


10

您已经有几个非常好的场景。

还有很多其他原因。EF确实擅长CRUD和非常直接的报告。但是,有时EF并不是完美的工具。考虑将存储过程与Entity Framework结合使用的其他一些原因(方案)包括:

  • 您有复杂的工作单元,可能涉及许多表,使用EF的功能无法轻松地将它们包装在事务中。
  • 您的数据库不能很好地与EF配合使用,因为它无法利用声明性参照完整性(外键约束)。通常,这是个糟糕的情况,但有时会有合适的情况,例如用于ETL流程的数据库。
  • 您需要处理与链接服务器跨越服务器边界的数据。
  • 您有非常复杂的数据检索方案,其中需要使用“裸机” SQL以确保足够的性能。例如,您有复杂的联接,需要查询提示才能在特定情况下正常工作。
  • 您的应用程序对表没有完全的CRUD权限,但是可以允许您的应用程序在服务器信任的安全上下文下运行(例如,应用程序身份,而不是用户身份)。在DBA仅将表访问限制为存储的proc的情况下,可能会出现这种情况,这是因为DBA可以使他们更精细地控制谁可以做什么。

我敢肯定,除了这些以外,还有更多。确定在任何特定情况下前进的最佳途径的方法是使用一些常识并专注于主要目标,即编写高质量,易于维护的代码。选择在每种情况下都能获得此结果的工具。


谢谢Joel,您提到了我没有想到的其他一些情况。
艾米·巴雷特

好答案。但是,我想知道您是否有许多用户连接到数据库并运行复杂的查询或存储过程,难道您最终会给数据库服务器带来很多负担吗?
Ripal Barot

1
@RipalBarot毫无疑问,工作负载(用户越多,查询越复杂)进行的越多,对数据库服务器的需求就越大。但是要记住的一件事是,使用存储过程而不是像Entity Framework这样的ORM可能会(相对)减轻工作量,因为存储过程可以具有预编译的查询计划。当查询来自ORM时,DBMS通常必须首先弄清楚如何处理查询。当您调用等效的存储过程时,数据库已经知道如何有效地实现它。
乔尔·布朗

2

解决问题并找到只有存储过程才能完成的用例,这才是您想要实现的。也许在真正的用例中,存储过程脱颖而出。

如果有所作为,我正在使用MSSQL和Entity Framework。

我在EF知识是有限的,但就我所看到的,EF是()像任何其他的ORM; 而幸运的是能够使用原始的SQL

如果我有两个要点:

一份复杂的报告需要几分钟才能运行(这是Web应用程序中的页面)。我发现我可以编写比LINQ提供的SQL更有效的SQL(只需花费几秒钟即可运行)。

编写报告时,LINQ / EF不足。正如您所注意到的,它SQL比使用ORM快得多。但这是说支持存储过程还是反对对所有内容使用ORM

您的问题显然可以使用SQL解决。根据您的示例,如果该查询已存储并在代码库中控制版本,则至少没有区别

一个Web应用程序需要读写一个单独数据库中的几个表,其中包含许多其他与该应用程序无关的敏感信息。我没有给它访问所有内容的权限,而是使用了一个存储过程,该过程仅执行所需的操作,并且仅返回有限的信息。然后,可以只给Web应用程序访问此存储过程的权限,而不能访问任何表等。

同样的事情:一个简单的连接字符串UPDATE,问题就解决了。这个问题可以解决,甚至有一个ORM只需使用一个Web服务在其他数据库前,同compartementalization / 隔离的实现。

所以没什么可看的。

查看其他人提出的一些观点:

您有复杂的工作单元,可能涉及许多表,使用EF的功能无法轻松地将它们包装在事务中。

但是SQL可以做到。这里没有魔术

您的数据库不能与EF配合使用

同样:在适当的时候使用EF

您需要处理与链接服务器跨越服务器边界的数据

我看不到,存储过程如何提供帮助。所以我看不到存储过程的优势;但也许有人对此有所启发。

您有非常复杂的数据检索方案,其中需要“裸机” SQL以确保足够的性能

再次:“ EF的边界”。

您的应用程序对表没有完全的CRUD权限,但是可以允许您的应用程序在服务器信任的安全上下文下运行

好的。我可能会去。

到目前为止,只支持存储过程一半


也许有性能方面的考虑,这有利于存储过程。

1)存储查询的好处是可以简单地调用存储过程,从而简化了复杂性。由于查询计划者知道查询,因此“轻松”进行优化。但是节省的是当前复杂的查询计划器_minimal。

最重要的是,即使使用即席查询会花费很少的钱,但是如果您的数据结构合理且经过精心索引,则数据库仅仅是应用程序的瓶颈。因此,即使增量较小,但考虑其他因素也可以忽略不计。

2)尽管如此,有人认为将复杂的查询存储在数据库中。有两件事要考虑:

a)复杂的查询大量使用数据库基础结构,这增加了其他每个查询的占用时间。您不能并行运行许多昂贵的查询。这既不赞成也不反对存储过程,但是反对复杂的查询。

b)如果查询仍然需要时间,那么为什么要以低速打扰存储过程呢?

tl; dr

没有什么直接反对存储过程。因此,使用存储过程是可以的-如果它使您满意。

但是,另一方面:我无法想象一个恰当的用例,它可以毫无疑问向人们讲。

什么时候应该使用存储过程?

正确的答案是:每当您喜欢时。但是还有其他选择。


0

对于您的特定情况,由于您正在使用实体框架,因此当实体框架无法满足要求或关注时,应考虑使用存储过程。

实体框架做得不错,性能将接近或等于使用存储过程。之所以选择实体框架,是因为您不想担心SQL,而是让该框架为您生成SQL。

但是,在某些情况下,实体框架可能无法满足您的需求。在这种情况下,将使用存储过程或参数化查询手动编写SQL,然后使用实体框架直接调用该存储过程/ SQL语句。

因此,除非正在使用的框架不能满足要求,否则我不会将任何东西移至存储过程。

我认为可能发生的最糟糕的事情是,人们选择使用实体框架,然后编写所有存储过程。现在,有一层没有任何价值的层。


100%同意最后一段
Ewan

0

有技术需求不是最可能的选择。程序员更喜欢他们的工具,通常更适应解决他们的问题。将逻辑放入存储过程将是一个例外。应该考虑技术债务和未来的开发人员必须花时间进行例外工作。您的特定RDBMS可能会提高性能,而这在存储过程中甚至可能在另一个数据库对象(如索引视图)中更容易实现。

有时候,您需要数据库中的数据,而您却无法从应用程序代码中获取数据。在许多大型公司/企业环境中,业务需求可能超出IT部门的控制范围。公司被买卖,他们的申请也随之而来。监管机构和银行不在乎您是否无法构建可高度扩展且编码精美的应用程序。它们会使企业的生活变得困难,因此您必须将其完成。

我遇到了第三方应用程序或报表编写工具不允许您使用代码的情况。没有开源代码,API,Web界面和服务。他们唯一拥有的是他们自己的特殊报表编写工具,该工具仅适用于数据库对象:表,视图,存储,用户定义的函数等。将逻辑放在任何可以获取的地方。

如果您的DBA非常擅长编写存储过程,则可以在某些情况下利用该人才。您可能要从应用程序触发备份,因为您将进行重大数据更改,那么为什么不使用dba的功能呢?

在您可以获取应用程序中的所有功能之前,某些临时请求更容易编写proc。我们讨厌它。我们向后推,但演出必须继续。


0

我强烈建议不要在存储过程中放置任何业务逻辑。但是,在某些情况下(您列出了两个很好的示例),最好在其中放置数据访问逻辑。

一般而言,如果您想使用SP,那是一个迹象(一种代码气味),暗示您的数据模型不太适合其需求。

编辑:当开发人员向我询问业务/数据访问逻辑时,我说业务逻辑与数据的行为和交互方式有关,而数据访问逻辑与数据的存储和检索方式有关。

例如:在您的域模型中,您可能具有实体“学生”和“教师”,这两个实体均源自“人”。(不说这是首选,只是一个例子)。可以将其作为一个,两个或三个表存储在关系数据库中。选择取决于它们共享多少个属性以及读/写性能要求。

在业务逻辑中,这些实体的存储方式无关紧要。(或者它们是否完全位于RDB中)。数据访问逻辑是关于它们如何物理存储的。

因此,关于原始问题:如果存储过程使存储和检索数据更有效(或更健壮),那么您会遇到一个问题。如果存储过程只是为了强加一个我不管数据如何存储都有效的规则,请避免使用它。它使您的代码更紧密地耦合到数据库。


2
您将如何定义业务逻辑数据访问逻辑?
艾米·巴雷特


@RobertHarvey感谢您的链接。数据访问层是否与数据访问逻辑相同?我问,因为在数据访问层中似乎并没有涉及很多实际逻辑,只是简单的CRUD操作。
艾米·巴雷特

@AmyBarrett:嗯,有时您在数据访问层中编写自定义方法,因此并不总是CRUD。
罗伯特·哈维

@RobertHarvey但是那些自定义方法不属于业务逻辑层吗?
艾米·巴雷特

-4

我认为这里有三个问题。

  1. SQL中的业务逻辑不好。即使它单独运行得更快,它也不会扩展。

  2. 传统上,应该始终将SPROC作为抽象层用于所有数据访问。使DBA能够引入性能或其他数据层更改,而不会影响正在使用的应用程序。

  3. EF在存储过程中表现不佳。通过从动态查询生成切换为Linq,您将失去很多“好的”功能和生产率的提高。

所以我的总体建议是

  • 对所有SQL查询使用SPROC,

  • 不要在其中加入业务逻辑或任何形式的循环,

  • 不要使用EF。


由于所有SQL都在数据库服务器上运行,因此您只能使用额外的数据库而不是额外的计算框进行扩展。
伊万

1
我知道了。但是,第一点纯粹是关于两个性能问题之间的权衡。但是有时候在性能方面,SQL解决方案显然是个成功之选,因此我不认为在此基础上如何将其绝对地认为是“不好的”。

1
说您有一个进行计算的Web服务。您可以在代码或sql中执行此操作。说sql在单次计算的直接测试中速度更快。但是,当服务用尽CPU时,它非常便宜且易于添加运行网络服务的第二,第三,第四..盒,但添加第二个复制数据库却又困难又昂贵
Ewan

1
这是一个特定场景的示例,其中由于可伸缩性,SQL 可能是一个糟糕的设计。但是即使如此,也不清楚:它取决于预期的用户数量,与外部数据库相比在数据库中执行计算的相对成本,等等。当然,在某些情况下您是正确的,我只是认为这不是普遍规则。

3
总体来说,这是个坏建议。与手动编码存储过程相比,有许多数据访问选项具有优势,并且执行效果也一样。您可以直接从EF运行sproc;实际上,您可以直接从EF 运行任何 SQL查询。一些业务逻辑在数据库服务器上运行得更好,因此您不能断然声明禁止在该服务器上使用。对象关系映射器是80%的工具;它们绝不是要完全取代您的数据访问过程。将存储过程用于它们的预期用途:ORM表现不好的20%。
罗伯特·哈维
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.