在SQL中放置逻辑的优点和缺点?

时间:2010-07-22 14:04:25

标签: sql

在一份新工作中,我刚刚接触到将逻辑放入SQL语句的概念。

在MySQL中,一个愚蠢的例子是这样的:

SELECT
    P.LastName, IF(P.LastName='Baldwin','Michael','Bruce') AS FirstName
FROM
    University.PhilosophyProfessors P
// This is like a ternary operator; if the condition is true, it returns 
// the first value; else the second value. So if a professor's last name 
// is 'Baldwin', we will get their first name as "Michael"; otherwise, "Bruce"**

对于一个更现实的例子,也许您正在决定销售人员是否有资格获得奖金。您可以获取各种销售数字并在SQL查询中进行一些计算,并返回true / false作为名为“qualifies”的列值。

以前,我会从查询中获取所有销售数据,然后在我的应用程序代码中完成计算。

对我而言,这似乎更好,因为如果有必要,我可以使用调试器逐步完成应用程序逻辑,但无论数据库在做什么,对我来说都是一个黑盒子。但我是初级开发人员,所以我不知道什么是正常的。

让数据库服务器执行某些计算/逻辑有哪些优缺点?

**基于Monty Python sketch.

的代码示例

13 个答案:

答案 0 :(得分:7)

这样 SQL就会成为域模型的一部分。它是实现领域知识的又一个(并不一定是显而易见的)地方。这种泄漏导致业务逻辑/应用程序代码和数据库之间的耦合更紧密,这通常是一个坏主意。

一个例外是观点,报告查询等。但这些通常是如此孤立,以至于它们扮演的角色显而易见。

答案 1 :(得分:7)

将逻辑推送到数据库的最有说服力的理由之一是最小化流量。在给出的示例中,几乎没有收获,因为无论逻辑是在查询中还是在应用程序中,您都在获取相同数量的数据。

如果您只想获取名字为Michael的用户,那么在服务器上实现逻辑会更有意义。实际上,在这个简单的示例中,它没有太大区别,因为您可以指定姓氏为Baldwin的用户。但是考虑一个更有趣的问题,即根据他们的名字和名字的常见程度给每个用户一个“受欢迎程度”分数,并且你想要获取10个“最受欢迎”的用户。在应用程序中计算“流行度”意味着您必须在排名,排序和在本地选择之前获取每个用户。在服务器上计算它意味着你可以在线上只获取10行。

答案 2 :(得分:3)

这个论点没有太多绝对的利弊,所以答案是'这取决于'。某些影响此决策的具有不同条件的方案可能是:

<强> Client-server app

可能适合这样做的地方的一个示例是较旧的4GLrich client应用程序,其中所有数据库操作都是通过基于存储过程的更新,插入,删除sprocs完成的。在这种情况下,体系结构的要点是让sprocs充当数据库的主要接口,并且与特定实体相关的所有业务逻辑都存在于一个地方。

这种类型的架构现在有些不合时宜,但有一次它被认为是最好的方式。许多VB, Oracle Forms, Informix 4GL以及此时代的其他客户端服务器应用程序都是这样完成的,它实际上运行得相当不错。

然而,它并非没有缺点 - SQL在抽象方面并不是特别擅长,因此很容易找到相当迟钝的SQL代码,这些代码通过难以理解而不像人们所希望的那样呈现出维护问题。

今天仍然有用吗?通常,富客户端是应用程序的正确平台,Winforms和Swing肯定会有大量新的开发。我们今天有很好的开源ORM,1995年的老式Oracle Forms应用程序可能没有选择使用这种类型的技术。然而,使用ORM的决定当然不是黑白分支 - 福勒的Patterns of Enterprise Application Architecture在运行一系列数据访问策略和讨论它们的相对优点方面做得相当不错。

具有丰富对象模型的三层应用

这种类型的应用程序采用相反的方法,并将中间层模型对象层中的所有业务逻辑放在一个相对较薄的数据库层(或者像ORM这样的现成机制中) 。在这种情况下,您尝试将所有应用程序逻辑放在中间层中。数据访问层的智能相对较少,除了少数存储过程需要绕过ORM的限制。

在这种情况下,基于SQL的业务逻辑保持最小,因为应用程序逻辑的主存储库是中间层。

过度批量处理

如果您必须执行periodic run来挑选符合某些复杂条件的记录并对其执行某些操作,则将其实现为存储过程可能是合适的。对于可能必须经过相当大小的数据库的重要部分的东西,基于sproc的approch可能是执行此类事情的唯一合理的性能方式。

在这种情况下,SQL可能是这样做的合适方式,尽管传统的3GL(特别是COBOL)是专门为此类处理而设计的。在真正高容量的环境(特别是大型机)中,使用数据库外部的平面或VSAM文件进行此类处理可能是最快的方法。此外,一些工作可能本质上是面向记录和程序性的,或者如果以这种方式实施,可能更加透明和可维护。

paraphrase Ed Post,'你可以用任何语言编写COBOL' - 尽管你可能不想这样做。如果你想将它保存在数据库中,请使用SQL,但它肯定不是城里唯一的游戏。

<强>报告

报告工具的本质倾向于规定编码业务逻辑的方法。大多数设计用于处理基于SQL的数据源,因此工具的性质迫使您选择。

其他域名

某些应用程序(如ETL处理)可能非常适合SQL。如果转换过于复杂,ETL工具开始变得无用,因此您可能希望选择基于存储过程的体系结构。在提取,ETL处理和基于存储过程的处理之间混合查询和转换可能会导致难以测试和排除故障的转换过程。

如果你在sprocs中有很大一部分逻辑,那么将所有逻辑放在其中可能会更好,因为它为你提供了一个相对同质和模块化的代码库。事实上,我拥有相当好的权力,银行和保险行业中大约一半的数据仓库项目都是以明确的设计决策方式完成的 - 正是出于这个原因。

答案 3 :(得分:2)

很多时候,这类问题的答案在很大程度上取决于部署方法。放置逻辑最有意义的地方取决于您在进行更改时能够访问的内容。

对于未编译的Web应用程序,处理页面或文件的更改比处理查询更容易(取决于查询复杂性,编程背景/专业知识等)。在这种情况下,脚本语言中的逻辑通常都可以,并且可以使以后更容易修改。

对于需要更多修改的桌面应用程序,将这种逻辑放在可以调整它的数据库中而无需重新编译应用程序可能会对您有所帮助。如果做出的决定是人们过去有资格获得20k的奖金,但现在必须赚25k,那么在SQL Server上调整它比在所有用户中重新编译会计应用程序要容易得多。

答案 4 :(得分:2)

我强烈主张将尽可能多的逻辑直接放入数据库中。这意味着将其合并到视图和存储过程中。我相信大多数都遵循DRY原则。

例如,考虑一个包含FirstName和LastName列的表,以及一个经常使用FullName字段的应用程序。你有三个选择:

  1. 查询名字和姓氏,并在应用程序代码中计算全名。

  2. 在查询表时,在应用程序的SQL中查询first,last和(first || last)。

  3. 定义一个CustomerExt视图,其中包含第一列和最后一列,以及计算的全名列,然后针对该视图而不是客户表进行查询。

  4. 我认为选项3显然是正确的。考虑在表中添加一个MiddleInitial字段和全名计算。使用选项3,您只需要替换视图,公司中的每个应用程序都将立即使用FullName的新格式。该视图仍然使基本列可用于您需要进行某些特殊格式化的实例,但对于标准实例,所有内容都“自动”工作。

    这是一个简单的案例,但对于更复杂的情况,原则是相同的。直接在数据库中执行应用程序或公司范围的数据逻辑,您无需担心将不同的应用程序保持最新。

答案 5 :(得分:1)

这个特别的第一个例子是一个坏主意。随着表变大,每行功能不能很好地扩展。事实上,(可能)更好的方法是索引LastName并使用类似的东西:

SELECT P.LastName, 'Michael' AS FirstName
    FROM University.PhilosophyProfessors P
    WHERE P.LastName = 'Baldwin'
UNION ALL SELECT P.LastName, 'Bruce' AS FirstName
    FROM University.PhilosophyProfessors P
    WHERE P.LastName <> 'Baldwin'

在数据读取频率高于写入的数据库(大多数数据),这些类型的计算应该在写入时完成,例如使用插入/更新触发器来填充真实的FirstName字段。

数据库应该用于存储和检索数据,而不是进行大规模的非数据库计算,这将减慢一切。

答案 6 :(得分:1)

答案取决于您的专业知识和您对所涉及技术的熟悉程度。此外,如果您是技术经理,则取决于您对团队成员的技能分析,以及您打算雇用/留住员工以支持,扩展和维护应用程序。 如果你没有识字和精通数据库,(因为你不是),那么坚持在代码中执行它。如果是otoh,你是识字并且精通数据库编码(正如你应该的那样),那么在数据库中进行这样做是没有错的(并且很多权利)。

可能影响您决策的另外两个注意事项是逻辑是否具有如此复杂的性质,以至于在数据库代码中执行它会比在代码中更复杂或更抽象,其次,如果涉及的过程需要来自外部的数据数据库(来自其他一些来源)在这些场景中的任何一个中,我都会考虑将逻辑移动到代码模块。

答案 7 :(得分:1)

您可以更轻松地单步执行IDE中的代码,这实际上是您的后处理解决方案的唯一优势。在数据库服务器中执行逻辑通常会大大减少结果集的大小,从而减少网络流量。它还允许查询优化器更好地了解您真正想要做的事情,同样通常可以提高性能。

因此我几乎总是会推荐SQL逻辑。如果你把一个数据库视为一个愚蠢的商店,它会通过表现愚蠢的方式来回报,并且根据情况,这绝对会扼杀你的表现 - 如果不是今天,可能是明年事情已经开始......

答案 8 :(得分:0)

一位大专业人士:您可以使用所有查询。已经提到报告:现有程序的许多报告工具或报告插件只允许用户自己进行查询(结果将显示在其中)。

如果您无法更改代码(因为它不是您的代码),您可能还可以更改查询。在某些情况下(数据迁移),您也将编写查询以进行迁移。

答案 9 :(得分:0)

我喜欢区分数据与业务规则,并尽可能将数据规则推送到存储过程中。两者之间并不总是存在硬性和快速的区别,但在计算销售奖金的例子中,公式本身可能是一个商业规则,但收集和汇总公式中使用的各种数字的工作是数据规则。 / p>

但有时候,它取决于部署模型和更改控制程序。如果销售公式频繁更改并且业务层代码的部署很麻烦,那么在数据库中调整一个函数/存储过程将是一个很好的解决方案。

答案 10 :(得分:0)

我对此并不完全确定,但是我想在SQL中放置复杂的写查询,因为这样一来,您就不必担心锁定太多了。

例如,如果您不能在某个状态下进行写操作,则可以在

中查询该状态。

答案 11 :(得分:0)

我非常喜欢优雅的数据库查询,因为代码更接近数据并且SQL运行得很好。但是,此类查询(无论是应用程序中的文本,由OR映射器生成还是存储在数据库中)更难以测试,尤其是在云中,因为您需要运行数据库。

答案 12 :(得分:0)

数据库就是它所说的。数据库。

您不应将业务逻辑与数据层混在一起。

将其分开,因为数据与业务之间的任何紧密耦合都无法遵循编程中的最佳标准。

我最近正在从事一个所有逻辑都在MS SQL中的项目。可怕的想法是,几年后事与愿违(能源公司),没有简单的横向扩展方法,没有简单的跟进CI / CD,敏捷或代码仓库的方法。很难合作,非常缓慢而且效率很低。

公司基本上是为了使其工作而达到硬件极限(他们已经在SSD SAN上花费了10万英镑),而使用C#可以达到相同的业务性能,并保留数据库来存储数据,大约3-4便宜的服务器,可以轻松地向外扩展。

一个可怕的想法。你猜怎么了 ?公司倒闭了,因为有一次SQL Server达到了它的潜力(有时一些查询运行了几个小时(写得很好,但SQL并不是为了业务逻辑。故事结束)),但是有一次却无法向所有DD客户收费没有拿到生存所需的每月付款(数百万英镑)。