假设您出于某种原因无法使用 LINQ,那么将查询放在存储过程中是否是更好的做法,或者执行起来也同样好 特别指定 针对数据库的查询(为了论证,例如 SQL Server)?

有帮助吗?

解决方案

根据我主要编写 WinForms 客户端/服务器应用程序的经验,这些是我得出的简单结论:

使用存储过程:

  1. 适用于任何复杂的数据工作。如果您要做的事情确实需要游标或临时表,那么在 SQL Server 中通常是最快的。
  2. 当您需要锁定对数据的访问时。如果您不向用户(或角色或其他)授予表访问权限,您可以确定与数据交互的唯一方法是通过您创建的 SP。

使用临时查询:

  1. 对于 CRUD,当您不需要限制数据访问(或以其他方式这样做)时。
  2. 用于简单搜索。为一堆搜索条件创建 SP 是一件痛苦且难以维护的事情。如果您可以生成相当快的搜索查询,请使用它。

在我的大多数应用程序中,我都使用了 SP 和 ad-hoc sql,但我发现我使用 SP 的次数越来越少,因为它们最终变成了像 C# 一样的代码,只是更难进行版本控制、测试和维护。我建议使用 ad-hoc sql,除非您能找到不这样做的具体原因。

其他提示

除了 SQL Server,我不能谈论任何其他东西,但性能参数是 不是 除非您使用的是 6.5 或更早版本,否则该版本非常有效。SQL Server 缓存临时执行计划已经有大约十年了。

存储过程代表一个软件契约,封装了对数据库采取的操作。过程中的代码,甚至数据库本身的模式都可以更改,而不会影响已编译、部署的代码,因此过程的输入和输出保持不变。

通过在应用程序中嵌入查询,您可以将自己与数据模型紧密耦合。

出于同样的原因,简单地创建针对数据库中每个表进行 CRUD 查询的存储过程也不是一个好习惯,因为这仍然是紧密耦合的。相反,这些过程应该是庞大的、粗粒度的操作。

从安全角度来看,最好禁止应用程序使用 db_datareader 和 db_datawriter,而只允许访问存储过程。

我认为这是必须维护数据库的人员和开发用户界面的人员之间的基本冲突。

作为一名数据人员,我不会考虑使用通过即席查询访问的数据库,因为它们很难有效地调整或管理。我如何知道架构更改会产生什么影响?此外,出于安全原因,我认为不应该授予用户直接访问数据库表的权限(我不仅仅指 SQL 注入攻击,还因为这是一种基本的内部控制,不允许直接访问权限并要求所有用户仅使用为应用程序设计的进程。这是为了防止可能的欺诈行为。任何允许对表直接插入、更新或删除权限的金融系统都存在巨大的欺诈风险。这是一件坏事。)。

数据库不是面向对象的,从面向对象的角度来看似乎不错的代码从数据库的角度来看可能非常糟糕。

我们的开发人员告诉我们,他们很高兴我们所有的数据库访问都是通过过程进行的,因为它可以更快地修复以数据为中心的错误,然后只需在生产环境上运行过程,而不是创建代码的新分支并重新编译和重新加载到生产环境。我们要求所有的过程都处于颠覆状态,因此源代码控制根本不是问题。如果它不在 Subversion 中,它会定期被 dbas 删除,因此使用源代码管理没有阻力。

存储过程绝对是要走的路......它们被编译,事先有执行计划,你可以对它们进行权限管理。

我不明白存储过程的整个源代码控制问题。只要你有一点自律,你绝对可以对它们进行源代码控制。

始终从作为存储过程源的 .sql 文件开始。编写代码后将其放入版本控制中。下次您想要编辑存储过程时,请从源代码管理而不是数据库中获取它。如果您遵循这一点,您将拥有与代码一样好的源代码控制。

我想在这里引用 Oracle 的 Tom Kyte...这是他关于在哪里编写代码的规则...虽然有点不相关,但我想知道还是很高兴的。

  1. 从 PL/SQL 中的存储过程开始...
  2. 如果您认为使用 PL/SQL 中的存储过程无法完成某些操作,请使用 Java 存储过程。
  3. 如果您认为使用 Java 存储过程无法完成某些操作,请考虑 Pro*c。
  4. 如果您认为使用 Pro*C 无法实现某些目标,您可能需要重新考虑需要完成什么。

在我们的应用程序中,有一层代码提供查询内容(有时是对存储过程的调用)。这使我们能够:

  • 轻松地将所有查询置于版本控制之下
  • 对不同数据库服务器的每个查询进行所需的更改
  • 消除了我们的代码中重复相同的查询代码

访问控制是在中间层实现的,而不是在数据库中实现的,因此我们不需要那里的存储过程。在某些方面,这是即席查询和存储过程之间的中间道路。

我的答案 来自不同的 邮政:存储过程是 更多的 可维护,因为:

  • 每当您想要更改某些 SQL 时,无需重新编译 C# 应用程序
  • 您最终会重用 SQL 代码。

代码重复是 最糟糕的 当您尝试构建可维护的应用程序时您可以做的事情!

当您发现多处逻辑错误需要纠正时会发生什么?您更容易忘记更改复制和粘贴代码的最后一个位置。

在我看来,性能和安全性的提升是一个额外的优势。 您仍然可以编写不安全/低效的 SQL 存储过程。

更容易移植到另一个数据库 - 无需移植

编写所有存储过程的脚本以便在另一个数据库中创建并不困难。事实上——它是 更轻松 而不是导出表,因为无需担心主键/外键。

两者都有有说服力的论据 - 存储过程都位于中央存储库中,但(可能)难以迁移,并且临时查询更容易调试,因为它们与您的代码一起使用,但它们也可能更难在代码。

存储过程更高效的论点不再成立。链接文本

对存储过程与动态查询进行谷歌搜索,无论哪种方式都会显示出不错的论据,并且可能最适合您做出自己的决定......

如果您将 SQL 编写到代码中,您已经为将来的麻烦做好了准备,那么应该尽可能多地使用存储过程。编写 SPROC 所需的时间与编写代码所需的时间大致相同。

考虑一个在中等负载下运行良好的查询,但一旦进入全职生产状态,优化不当的查询就会严重影响系统并使其陷入瘫痪。在大多数 SQL 服务器中,您并不是唯一使用它的应用程序/服务。你的申请现在已经把一群愤怒的人带到你家门口了。

如果您在 SPROC 中进行查询,您还可以让友好的 DBA 进行管理和优化,而无需重新编译或破坏您的应用程序。请记住,DBA 是该领域的专家,他们知道该做什么、不该做什么。利用他们更丰富的知识是有意义的!

编辑:有人说重新编译是懒惰的借口!是的,让我们看看当您必须重新编译应用程序并将其部署到 1000 个桌面时,您感觉有多懒,这一切都是因为 DBA 告诉您您的即席查询占用了太多服务器时间!

有人说重新编译是懒惰的借口!是的,让我们看看当您必须重新编译应用程序并将其部署到 1000 个桌面时,您感觉有多懒,这一切都是因为 DBA 告诉您您的即席查询占用了太多服务器时间!

如果让1000个桌面直接连接数据库,这样的系统架构好吗?

这里需要考虑一些事情: 无论如何,谁需要存储过程?

显然,这是您自己的需求和偏好的问题,但在面向公众的环境中使用即席查询时需要考虑的一件非常重要的事情是安全性。始终对它们进行参数化并注意典型的漏洞,例如 SQL注入攻击.

存储过程很棒,因为无需重新编译即可更改它们。我会尝试尽可能多地使用它们。

我仅对根据用户输入动态生成的查询使用临时查询。

由于其他人提到的原因,过程也更容易使用探查器或过程的一部分来调整过程。这样您就不必告诉某人运行他的应用程序来找出正在发送到 SQL Server 的内容

如果您确实使用临时查询,请确保它们已参数化

参数化 SQL 或 SPROC...从性能角度来看并不重要...您可以查询优化其中任何一个。

对我来说,SPROC 的最后一个好处是,我可以通过仅授予执行存储过程的登录权限来消除大量 SQL 权限管理...如果您使用参数化 SQL,则使用连接字符串的登录将拥有更多权限(写入 ANY例如,他们也可以访问的表之一上的一种 select 语句)。

不过我还是更喜欢参数化 SQL...

我还没有发现任何使用即席查询的令人信服的论据。尤其是那些与 C#/Java/PHP 代码混合的代码。

sproc 性能参数没有实际意义 - 前 3 个 RDBM 使用查询计划缓存并且已经使用了一段时间。它已被记录...还是1995年仍然如此?

然而,在应用程序中嵌入 SQL 也是一个糟糕的设计 - 对于许多人来说,代码维护似乎是一个缺失的概念。

如果应用程序可以使用 ORM 从头开始​​(绿地应用程序非常少!),那么它是一个不错的选择,因为您的类模型驱动您的数据库模型 - 并且节省大量时间。

如果 ORM 框架不可用,我们会采取混合方法创建 SQL 资源 XML 文件来查找我们需要的 SQL 字符串(然后它们由资源框架缓存)。如果 SQL 需要任何较小的操作,则可以在代码中完成 - 如果需要主要的 SQL 字符串操作,我们会重新考虑该方法。

这种混合方法使开发人员可以轻松管理(也许我们是少数,因为我的团队足够聪明,可以阅读查询计划),并且部署是从 SVN 进行的简单检查。此外,它使切换 RDBM 变得更容易 - 只需换出 SQL 资源文件(当然不像 ORM 工具那么容易,但可以连接到遗留系统或不受支持的数据库)

取决于你的目标是什么。例如,如果您想要检索项目列表,并且该操作在应用程序的整个运行过程中只发生一次,则可能不值得使用存储过程。另一方面,重复运行并需要(相对)较长时间执行的查询是数据库存储的绝佳候选者,因为性能会更好。

如果您的应用程序几乎完全位于数据库中,那么存储过程是理所当然的。如果您正在编写一个桌面应用程序,而数据库对其来说只是无关紧要的,那么临时查询可能是一个更好的选择,因为它 将所有代码保存在一处.

@Terrapin:我认为您的断言“您不必重新编译应用程序来进行修改”使存储过程成为更好的选择这一事实是行不通的。选择存储过程而不是临时查询可能是有原因的,但在没有其他令人信服的东西的情况下,编译问题看起来像是懒惰而不是真正的原因。

我的经验是,90% 的查询和/或存储过程根本不应该编写(至少不应该手工编写)。

数据访问应该以某种方式自动生成。您可以决定是否要在编译时静态生成过程或在运行时动态生成过程,但是当您想要向表添加列(对象的属性)时,您应该只修改一个文件。

我更喜欢保留所有数据 使用权 程序代码中的逻辑,其中数据访问层执行直接 SQL 查询。另一方面,数据 管理 我以触发器、存储过程、自定义函数等形式放入数据库的逻辑。我认为值得数据库化的一个例子是数据生成 - 假设我们的客户有名字和姓氏。现在,用户界面需要一个 DisplayName,它源自一些重要的逻辑。对于这一代,我创建了一个存储过程,然后每当更新行(或其他源数据)时就会由触发器执行该存储过程。

似乎存在这样一种常见的误解:数据访问层就是数据库,有关数据和数据访问的所有内容都“只是因为”而存在。这完全是错误的,但我看到很多设计都是源于这个想法。不过,也许这是当地的现象。

在看到这么多设计糟糕的 SP 后,我可能就不再考虑 SP 的想法了。例如,我参与的一个项目对每个表和遇到的每个可能的查询使用了一组 CRUD 存储过程。在这样做的过程中,他们只是添加了另一个完全毫无意义的层。这些事情连想想都让人痛苦。

这些天我几乎不再使用存储过程。我只将它们用于复杂的 SQL 查询,这些查询无法在代码中轻松完成。

主要原因之一是存储过程不能很好地与 OR 映射器配合使用。

如今,我认为您需要一个很好的理由来编写不使用某种 OR 映射器的业务应用程序/信息系统。

存储过程作为代码块工作,因此代替即席查询,它可以快速运行。另一件事是存储过程提供重新编译选项,您只需将其用于存储过程中的最佳部分,而在Adhoc查询中没有什么。

查询和存储过程的某些结果是不同的,这是我个人的经验。使用强制转换和隐藏函数来检查这一点。

大项目必须使用存储过程来提高性能。

我的项目中有 420 个程序,它对我来说工作得很好。我在这个项目上工作了三年。

因此,任何交易仅使用程序。

如果让将1000个台式机直接连接到数据库,它是不错的系统体系结构吗?

不,显然不是,这可能是一个糟糕的例子,但我认为我想表达的观点很清楚,你的 DBA 会照顾你的数据库基础设施,这是他们的专业知识,在代码中填充 SQL 会锁住他们和他们的专业知识的大门。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top