
Which is better: Ad hoc queries or stored procedures?假设由于某种原因不能使用LINQ,将查询放置在存储过程中是更好的做法,还是对数据库执行临时查询(例如,为论证而使用SQL Server)是否一样好? 以我主要编写WinForms客户端/服务器应用程序的经验,这些是我得出的简单结论: 使用存储过程: 使用临时查询: 在我的大多数应用程序中,我同时使用了SP和临时sql,尽管我发现越来越少使用SP,因为它们最终像C#一样是代码,因此版本控制,测试和维护变得更加困难。我建议使用临时sql,除非您找到特定的原因。 除了SQL Server,我只能说其他任何东西,但是性能参数在那里不是很有效,除非您使用的是6.5或更早版本。 SQL Server已经缓存了临时执行计划大约十年了。 我认为这是必须维护数据库的人员与开发用户界面的人员之间的基本冲突。 作为数据人员,我不会考虑使用通过即席查询访问的数据库,因为它们很难有效地进行调整或管理。我怎么知道更改架构会有什么影响?此外,出于安全原因,我不认为应该授予用户直接访问数据库表的权限(我不仅指SQL注入攻击,还因为它是基本的内部控件,不允许直接权限,并且要求所有用户仅使用为该应用程序设计的proc。这是为了防止可能的欺诈行为。任何允许直接插入,更新或删除表的权限的财务系统都存在巨大的欺诈风险(这是一件坏事。)。 数据库不是面向对象的,而从面向对象的角度看似乎不错的代码从数据库的角度来看可能非常糟糕。 我们的开发人员告诉我们,我们对所有的数据库访问都是通过proc感到很高兴,因为它可以更快地修复以数据为中心的bug,然后仅在生产环境中运行proc,而不是创建代码的新分支并重新编译和重新投入生产。我们要求所有过程都在Subversion中,因此源代码控制根本不是问题。如果不在Subversion中,它将被dbas定期删除,因此不存在使用Source Control的阻力。 存储过程表示一种软件合同,其中包含对数据库采取的操作。可以更改过程中的代码,甚至可以更改数据库本身的模式,而不会影响已编译的已部署代码,因此过程的输入和输出保持不变。 通过在应用程序中嵌入查询,可以将自己与数据模型紧密耦合。 出于同样的原因,对数据库中的每个表简单地创建只是CRUD查询的存储过程也不是一个好习惯,因为这仍然是紧密耦合的。该程序应改为笨重的粗粒度操作。 从安全角度来看,优良作法是禁止从应用程序中使用db_datareader和db_datawriter,而仅允许访问存储过程。 存储过程绝对是必经之路...它们经过编译,事先有执行计划,您可以对其进行权限管理。 我不了解存储过程中的整个源代码管理问题。如果只有一点点的纪律,您绝对可以控制它们。 始终以.sql文件开头,该文件是存储过程的源。编写代码后,将其放入版本控制中。下次要编辑存储过程时,请从源代码管理而不是数据库中获取它。如果遵循此步骤,您将拥有与代码一样好的源代码控制。 我想在这里引用来自Oracle的Tom Kyte ...这是他在哪里编写代码的规则...虽然有点无关但我想知道。 在我们的应用程序中,有一层代码提供查询的内容(有时是对存储过程的调用)。这使我们能够:
访问控制是在中间层而不是数据库中实现的,因此我们不需要那里的存储过程。在某些方面,这是临时查询和存储的过程之间的中间道路。
我从另一个帖子中得到的答案是:
尝试构建可维护的应用程序时,代码重复是最糟糕的事情! 当您发现需要在多个地方纠正的逻辑错误时,会发生什么?您更容易忘记更改复制和粘贴代码的最后一个位置。 我认为,性能和安全性方面的收益是额外的优势。您仍然可以编写不安全/效率低下的SQL存储过程。
将所有存储过程编写脚本以在另一个数据库中创建并不是很困难。实际上-因为没有主键/外键值得担心,所以比导出表更容易。 这两种说法都有说服力-存储过程都位于中央存储库中,但是(可能)难以迁移,并且临时查询与您的代码一样容易调试,但是在数据库中也很难找到它们。码。
关于存储过程更有效的争论不再成立。 为存储过程与动态查询做一个Google会以任何方式显示体面的参数,并且可能最适合您做出自己的决定... 如果您将SQL编写为代码,则已经准备好应付将来的麻烦了,应该尽可能使用存储过程。编写SPROC所需的时间与用代码编写SPROC所需的时间相同。 考虑一个在中等负载下运行良好的查询,但是一旦投入全职生产,您的优化不佳的查询就会影响系统并将其抓取。在大多数SQL Server中,您不是唯一使用它的应用程序/服务。现在,您的应用程序使一堆生气的人到了您家门口。 如果您在SPROC中有查询,则还允许友好的DBA进行管理和优化,而无需重新编译或破坏应用程序。请记住,DBA是该领域的专家,他们知道该做什么和不该做什么。利用他们的更多知识很有意义! 编辑:有人说重新编译是一个懒惰的借口!是的,让我们看看您需要重新编译并将应用程序部署到1000个台式机时的感觉有多懒,这都是因为DBA告诉您您的即席查询占用了太多服务器时间!
如果让1000个台式机直接连接到数据库,这是一种好的系统体系结构吗? 这里要考虑一些事情:到底谁需要存储过程? 显然,这是您自己的需求和偏好的问题,但是在面向公众的环境中使用临时查询时要考虑的一个非常重要的事情是安全性。始终对它们进行参数设置,并注意诸如SQL注入攻击之类的典型漏洞。 我还没有发现任何使用临时查询的引人注目的论点。特别是那些与您的C#/ Java / PHP代码混合在一起的代码。 sproc性能参数没有意义-3个顶级RDBM使用查询计划缓存并且已经存在了一段时间。它被记录在案...还是1995年还在? 但是,在您的应用程序中嵌入SQL也是一个糟糕的设计-代码维护似乎对于许多人来说都是缺失的概念。 如果应用程序可以使用ORM从头开始(绿地应用程序之间相距无几!),那么它是一个不错的选择,因为您的类模型可以驱动数据库模型-并节省大量时间。 如果没有ORM框架,我们将采用创建SQL资源XML文件的方式混合使用,以根据需要查找SQL字符串(然后由资源框架对其进行缓存)。如果SQL需要任何较小的操作,则可以在代码中完成-如果需要较大的SQL字符串操作,我们将重新考虑该方法。 这种混合方法使开发人员易于管理(也许是少数,因为我的团队足够聪明来阅读查询计划),并且部署是SVN的简单结帐。而且,它使切换RDBM更加容易-只需换出SQL资源文件(当然不如ORM工具那么简单,但可以连接到旧系统或不受支持的数据库) 存储过程很棒,因为无需重新编译就可以更改它们。我会尝试尽可能多地使用它们。 我仅将临时查询用于根据用户输入动态生成的查询。 参数化的SQL或SPROC ...从性能的角度来看并不重要...您可以查询优化其中之一。 对我来说,SPROC的最后一个好处是我可以通过仅授予我的登录权限来执行sprocs来消除很多SQL权限管理...如果您使用参数化SQL,则带有连接字符串的登录名将具有更多的权限(写ANY例如,它们也可以访问其中一个表的一种select语句)。 我仍然更喜欢参数化SQL ... 由于其他人提到的原因而对Procs进行处理,并且使用事件探查器或proc的某些部分来调整proc更加容易。这样,您就不必告诉某人运行他的应用程序来查找发送到SQL Server的内容。 如果您确实使用临时查询,请确保已对其进行了参数化 我更喜欢将所有数据访问逻辑保留在程序代码中,其中数据访问层执行直接的SQL查询。另一方面,我将数据管理逻辑以触发器,存储过程,自定义函数之类的形式放入数据库中。我认为值得数据库验证的一个例子是数据生成-假设我们的客户有一个名字和一个姓氏。现在,用户界面需要一个DisplayName,它是从一些平凡的逻辑派生而来的。对于这一代,我创建一个存储过程,每当更新行(或其他源数据)时,该触发器便由触发器执行该存储过程。 似乎存在一些常见的误解,即数据访问层是数据库,而有关数据和数据访问的所有内容都"因为"而进入了数据库。这是完全错误的,但是我看到很多设计都源于这个想法。不过,也许这是局部现象。 在看到了很多设计不当的SP之后,我可能只是关闭了SP的想法。例如,我参与的一个项目为每个表及其遇到的每个可能的查询使用了一组CRUD存储过程。这样,他们只是添加了另一个完全没有意义的层。甚至想到这些事情都是痛苦的。 这些天,我几乎从未使用过存储过程。我仅将它们用于无法通过代码轻松完成的复杂sql查询。 主要原因之一是因为存储过程在OR映射器中无法正常工作。 这些天,我认为您需要一个非常充分的理由来编写不使用某种OR映射器的业务应用程序/信息系统。 取决于您的目标是什么。例如,如果要检索项目列表,并且该列表在应用程序的整个运行过程中发生一次,那么使用存储过程可能就不值得了。另一方面,重复执行并且花费(相对)较长时间执行的查询是数据库存储的理想选择,因为性能会更好。 如果您的应用程序几乎完全存在于数据库中,那么存储过程就不费吹灰之力了。如果您正在编写一个桌面应用程序,而数据库仅对数据库有重要意义,那么临时查询可能是一个更好的选择,因为它将所有代码都放在一个地方。 @Terrapin:我认为您断言无需重新编译应用程序即可进行修改这一事实使存储过程成为一个更好的选择,这是毫无用处的。在临时查询中可能有选择存储过程的原因,但是在没有其他任何令人信服的情况下,编译问题似乎是懒惰而不是真正的原因。
存储过程作为代码块工作,因此可以代替即席查询快速运行。
查询和存储过程的某些结果不同,这是我个人的经验。 必须对大型项目使用存储过程以提高性能。 我的项目中有420个程序,对我来说很好。我在这个项目上工作了三年。 因此,仅对任何交易使用过程。 我的经验是90%的查询和/或存储过程都不应该(至少用手)编写。 数据访问应该以某种方式自动生成。您可以决定是要在编译时静态生成过程还是在运行时动态生成过程,但是当您想向表中添加列(对象的属性)时,您应该只修改一个文件。
不,显然不是,这可能是一个糟糕的例子,但我想我想说的很清楚,您的DBA照料您的数据库基础架构是他们的专长,将SQL塞入代码中为他们和他们的专长上锁了。 |