在没有存储过程或触发器的情况下工作
Posted
技术标签:
【中文标题】在没有存储过程或触发器的情况下工作【英文标题】:Working without stored procedures or triggers 【发布时间】:2010-09-18 18:24:47 【问题描述】:过去 18 个月来,我们一直致力于开发复杂的数据库和客户端界面。我们会定期向此应用程序添加新功能,现在每天都有数十名用户在我们的所有办公室(包括站点和海外)使用。这只是告诉您它是一个带有真实数据库的真实应用程序。
到目前为止,我们仍然不需要编写任何存储过程,除了临时解决客户端版本和更新数据库模型之间的小问题(旧客户端版本不会正确更新新创建的字段,直到大家安装最新版本)。
同样,我们仍然不需要任何触发器。事实上,唯一的 SP 和触发器是系统的,或者是为了复制目的而添加的。
当开发人员认为数据库优化必须反对数据库规范化时,我有一种奇怪的感觉,即 SP 和触发器主要用于补偿数据库设计默认值和/或试图绕过数据库设计规则。
问题在于这些工具非常耗时(无论是开发还是维护)。然后每个开发人员都应该非常小心地使用它们,记住它们是数据库中维护的最“昂贵”的项目。
我们是否可以认为数据库中没有或很少存储过程/触发器是其规范化水平和/或代码维护成本的良好指标?
编辑:
你们中的一些人为触发器和 SP 的使用提供了公平的论据。但我一直认为大部分时间这些工具的使用方式不当或过度。设置了多少触发器来在表字段之间进行一些花哨的更新,或者重新计算总计或其他聚合数据?有多少 SP 用于构建用于报告问题的临时表?这是开发人员使用这些工具的许多情况中的两种,我认为这通常说明数据库设计/规范化缺陷。
其他一些人承认应该严格控制 SP 和触发器的使用。我也觉得有必要。
我必须承认,我正试图找到一些支持的论点,所有这些在我们其他数据库上工作的 SQL 极客都看不起我们,告诉他们的朋友“你知道吗?他们甚至不使用 SP 和触发器!哈哈! "
【问题讨论】:
为什么标题中的“目标:”前缀? 你是对的。 “目标”是一种“法国式”错误! 我不明白您为什么认为使用存储过程来构建临时表以用于报告目的是不好的。有时这是在合理时间内完成报告的唯一方法(尤其是对于非常大的数据库)。 好吧,我相信这是因为我们从来不需要这样做!在必须构建临时表的极少数情况下,我们在客户端构建它,然后将其显示在屏幕上(这是一个环保选项),如果需要,从客户端的临时表中打印出来数据。 【参考方案1】:“设置了多少触发器来在表格字段之间进行一些花哨的更新,或者重新计算总计或其他聚合数据?”
使用触发器根据业务规则进行复杂的更新并不是一个缺陷。这是首选方法。如果要维护数据完整性,则应在数据库级别强制执行所有业务规则。除了用户界面之外,还有其他方法可以影响数据库中的数据,无论使用哪种方法,都应该应用业务规则。这样,导入的数据必须遵守规则,新功能必须遵守规则(而不是必须记住有规则并找到您为执行它而构建的功能),人们从查询工具批量更新数据(认为将所有价格提高 10%)将必须遵守规则等。
如果您没有单独的报告数据库,通常会重新计算总计以加快报告速度。当财务部门运行需要数小时才能运行的季度报告时,您是否想放慢或锁定整个数据库,因为他们必须根据数百万条记录计算总计?还是您宁愿对数据的每次更改都多花一秒钟的时间?这通常是一种仅在数据库变大并且在它变得足够大以证明拥有单独的报告数据库的成本之前才使用的方法。因此,是的,这是一种临时权宜之计,但是当您从原始设计转移到新设计时,这对于保持业务运行非常必要(构建 OLAP 需要相当长的时间和一套不同的技能)数据库)。
【讨论】:
【参考方案2】:如果您有七个不同的应用程序都与用户数据库通信,那么使用一个名为“createUser”的存储过程而不是七个不同的应用程序自己构建该 INSERT 语句不是更有意义吗?
现在,一个新应用程序必须将用户添加到此数据库,但它有一个新要求,需要添加一个新字段,即默认值是从存储在完全不同的第 3 方中的值填充的应用程序的数据库。
现在,你去改变这七个应用程序,加上新的一个,与第 3 方应用程序对话以获取价值,同时构建 INSERT 语句。
或者,您可以修改 users 数据库的 createUser proc 以从 3rd 方数据库中查找数据作为默认值,因此您的其他程序都不需要更改和重新部署,因为它们并不真正关心该值……还没有。
或者,您可以在用户表更新时向用户数据库添加触发器,以从第 3 方数据库中获取该值。
存储过程还具有编译的好处,因此比常规语句更快。
存储过程还可以将单个复杂的 sql 语句分解为几个更简单的语句,以提高查询的运行速度。
当数据需求发生变化时,修改存储过程要比更新应用程序的 1000 次安装简单得多。
我的 $.02
ps。 多年来我没有在应用程序中编写过一行 sql。这一切都在存储过程中。无论是简单的选择、插入、更新、复杂的报表,还是应用程序中实际上是单个对象但存储在数据库中 7 个不同表中的更新。
【讨论】:
我也好多年没有在应用程序中写过一行sql了。但是,我没有把它放在存储过程中。我不喜欢将我的应用程序需求拖到不属于它们的数据库中。我的应用程序中有用于数据访问的工具,只要数据结构规范化且灵活,就可以处理几乎所有我可以扔给它们的东西。使用 SOA 技术或 ClickOnce 之类的部署工具,我也没有 1000 多个安装需要更新。由于人们已经为我解决了这些问题,我得到了很好的照顾。【参考方案3】:我们是否可以认为数据库中没有或很少存储过程/触发器是其规范化水平和/或代码维护成本的良好指标?
不,你不能。
规范化和存储过程是完全分开的。
我对 SP 的看法是数据库和使用它的人之间的抽象层。
强制人们使用 SP 而不是直接的 CRUD 操作将更容易更改表的设计而不会破坏它们。
【讨论】:
我完全同意存储过程非常适合在更新可能来自不同程序的情况下使用。它们还允许部署大量更改,而最终用户无需更新版本。 我完全不同意你的观点!使用 SP 来“更容易更改表格的设计”通常证明它们用于补偿设计/规范化缺陷......否则,您为什么要更改表格的设计? 当您说 SP 是数据库和人员之间的抽象层时,客户端应用程序也是如此。我们真的需要这两层抽象吗? “你为什么要改变你的桌子的设计?”由于用户的新要求,以前不需要怎么办?这种情况发生的频率比你想象的要多…… 另一个非常有用的 op SP 是一种无需公开您的数据库设计即可直接访问您的数据库的方法。当您要将数据库链接到外部系统时,通常会这样做【参考方案4】:我们有一个我正在工作的程序,我认为这是一个很好的触发器案例,因为现在大约有 8 多个不同的版本(一个 API 和许多版本的前端和后端)。如果我想改变它处理某些东西的方式,如果它在触发器中,而不是必须在 8 个以上不同的代码库中做出完全相同的改变(意大利面条编码的水平不同),那会容易得多和命名不佳的变量)。
【讨论】:
【参考方案5】:这是一个绝对需要 SP 的示例:用户界面只是整个应用程序的一小部分。并且当整个过程独立于用户发生时。 例如,我从事一个涉及大量数据处理的项目,这些数据来自许多不同的来源。所以我们收到这些文件,然后我们只运行一个脚本外壳,它将简单地启动一个 SP 来从文件中导入所有数据,检查它们,操作它们等等...... 你猜怎么着?用户也可以从用户界面使用相同的 SP,而无需再次重写整个数据处理查询!
当然,如果那些处理查询只是简单的SELECT,那么你可以争论SP的必要性,但是当你需要更新几十个表,计算字段,清除数据,清理数据时,SP就很幸运了。这并不意味着我们的数据库缺乏规范化,但是当您每天处理数十亿数据时,并非一切都可以简单。
【讨论】:
【参考方案6】:至于存储过程,我们不要忘记安全问题。允许应用程序运行内联 SQL 意味着您的用户帐户需要直接读取、插入、更新和删除所有表的访问权限。如果发生违规行为,您的数据库就会暴露出来。
触发器有它们的位置。尤其是在有很多数据库开发人员可能知道也可能不知道(例如)我们保留预算信息更改历史记录的 SOX 要求的环境中。
【讨论】:
我们能否通过说我们需要知道“哪些数据被更改/由谁/何时更改”来恢复 SOX 要求。我们的客户端应用程序有一个“事务”对象,每次提交事务时都会在“事务表”中发送一条记录。然后我们有一个“历史”模块来分析归档的 SQL 指令。 如果您的任何业务逻辑更改可能需要通过不同的机制更新相关表,您可能需要重新调整您的事务对象。也许这对你来说是件好事。我自己不经常使用触发器。不过,我很高兴我有这个选择。【参考方案7】:没有什么比在代码中遇到大量包含错误的内联 SQL 更让我讨厌的了。至少使用存储过程,您可以对其进行语法检查,甚至可以执行它以查看问题所在。更不用说在保存执行计划时它会比仅仅在数据库中触发查询更快。我一直认为DB代码属于DB,但这只是我的观点。
触发器也有其用途。它们并不总是最好的,但肯定是有原因的。
【讨论】:
根据我自己的经验,代码中的大量内联 SQL 通常与花哨的数据操作相关联,这主要发生在数据库规范化程度不佳或客户端应用程序不尊重数据模型的情况下(例如:数据库中的记录将是客户屏幕上的列) 我可以反驳——如果你的数据库被正确规范化,你可能需要连接很多表来获得结果——这会导致大量的内联 SQL。【参考方案8】:如何从数据库中取回数据?你会构建 SQL 字符串并执行它们吗?如果是这样,您如何验证条目不会破坏数据库?存储过程有助于大大降低这种风险,因为服务器将文本作为文本而不是作为命令处理。
存储过程通常比对数据库执行 SQL 字符串快得多,这也意味着您不必为不同的信息组编写不同的选择,因为它都可以由存储过程完成。从程序中抽象出数据库的能力也是一个被多次提出的好处。
最后,我真的只使用触发器进行数据库审计(在 SQL2005 之前没有内置审计功能),它将使用每次更改的 prev 和新值更新表。
规范化和优化与存储的过程或触发器无关,规范化和优化可能会影响您需要抽象数据库的程度,但在我看来,每次更改数据库时都必须重构代码比使用存储过程
【讨论】:
基本上,客户端界面会即时构建 INSERT、UPDATE 和 DELETE,比较本地记录集和表结构。它不允许花哨/多个表更新,但使用干净的数据模型非常有效。大约 18 个月前,我们不再担心验证程序 “花式/多表更新”?如果您的数据库已标准化,您如何处理与另一位数据具有多对多关系的数据更新?【参考方案9】:存储过程和触发器是工具——在数据库管理系统中使用的非常具体的工具。
触发器有多种用途,从大大简化 历史 表的维护(其中每一行代表主表的过去一段时间)到将 ETL 请求排队到数据仓库(取决于具体的 RDBMS)
存储过程也有自己的位置,无论它们是从应用程序调用还是从 SQL 命令行工具调用。
包含存储过程或触发器实际上与规范化或“数据库设计默认值”无关。它们在应用程序中的使用通常与应用程序的其他要求直接相关,即可扩展性、可靠性、复制或其他要求可以通过使用这些工具最有效地满足。
如果您不需要它们,请不要使用它们。但是,不要假设触发器或存储过程的存在表明设计不佳。
【讨论】:
完全同意。它们可以被使用(但不能被滥用)。 我很欣赏你关于触发器的论点。【参考方案10】:没有。存储过程和触发器以许多不同的方式使用。这取决于环境、开发人员等。例如,存储过程通常用作安全机制。
我认为唯一适合使用触发器的地方是重构数据库时。所以也许你在这一点上有所作为。但其他人可能会以其他方式使用它们。
【讨论】:
谨慎使用,触发器有自己的位置;审计浮现在脑海中。 你是对的。在某些情况下,审计是另一个很好的用途。以上是关于在没有存储过程或触发器的情况下工作的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server基础操作(此随笔仅作为本人学习进度记录十 !--触发器)