SQL vs NoSQL:除了ACID和可扩展性之外的其他问题呢?

时间:2014-04-26 08:35:02

标签: sql conceptual nosql

我最近阅读了很多文章,其中描述了两个方面的SQL和NoSQL,例如http://use-the-index-luke.com/blog/2013-04/whats-left-of-nosql。这些文章经常涉及ACID和可伸缩性等主题。但是,我通常在SQL中遇到的一些问题似乎很少在这些文章中提及,我想知道为什么,以及这是否与我不完全理解SQL有关。如果有人能够启发我,至少部分是基于以下一项或多项,我将非常感激。

我的SQL问题:

  1. SQL本质上是不安全的:SQL是一种用于插入的语言,没有任何方法可以防止插入代码而不是数据。防止插入的唯一方法是使用它将SQL与应用程序完全隔离。为什么SQL本身还没有解决这个问题呢?
  2. SQL似乎是针对其中包含的数据可能的最小存储大小而制作的。虽然这对于大量数据仍然有很大意义,但它不再适用于较小的数据库,或者它是什么?
  3. SQL强制所有内容适合二维关系模型,使用特定关系表来执行其他维度。对我来说,这有两个问题:
    • 数据的一致性完全依赖于关系表
    • 在失败的情况下,人类很难理解数据
  4. SQL不维护历史记录,因为默认情况下会进行破坏性更新:当然有各种方法来创建历史记录,但这需要使用额外的表格和使用时间戳来自定义编写的东西,或者编写每个变化的新记录,导致表格大小呈指数级增长。
  5. SQL似乎更倾向于丢失数据丢失:如果发生错误或丢失一致性,将情境恢复到一致状态的唯一方法是使用备份,这意味着最新的更改将被销毁。这在一定程度上是因为缺乏历史(见4),但由于缺乏人类的可读性,没有真正的方法让人类尝试纠正错误。
  6. 特别是在Web环境中,SQL的使用通常意味着经常创建模型多次。在普通(简单)PHP Web应用程序中两次:一次在PHP中,一次在SQL中。在完整堆栈Web应用程序中三次:一次在客户端应用程序中,一次在中间件中,一次在SQL数据库中(如果没有使用ORM)。由于编程语言不同,以及它们之间的类型差异,这意味着这些模型之间存在很多可能的冲突。我知道像ActiveRecord和Django这样的ORM解决了这些问题中的至少一部分,但是由于SQL表包含VARCHAR(25)并且没有使用任何语言(JavaScript,Ruby,PHP),您还需要做额外的工作量。 ,Perl,Python等)知道那种构造,是巨大的。
  7. 数据结构更改似乎被视为一致性问题:如果数据结构中的某些内容发生更改,表更改将应用​​于该表中的每个现有记录,即使记录最初没有该字段以及是否拥有该领域的记录是有意义的。一组这些更改会导致自动迁移,这会增加另一层可能的问题,尤其是在一致性方面。
  8. 混合存储逻辑和应用程序逻辑:SQL似乎急于将应用程序逻辑的一部分吞噬为存储过程(CouchDB也通过视图执行此操作)。 虽然我知道对于某些类型的操作,您需要服务器端和非常严格控制的过程,但我不明白为什么它们存储在数据库中并作为存储引擎的一部分,而不是作为应用程序的一部分(中间件)。
  9. 我知道(但不是很熟悉)像PostgreSQL Hstore这样的东西,但我并没有完全看到它如何解决上面提到的问题。 感谢您的任何见解!

2 个答案:

答案 0 :(得分:19)

  1. SQL固有的不安全吗?

    我认为你指的是SQL Injections,这是最危险的安全漏洞之一。

    然而,SQL注入主要是教育问题,因为大多数教科书和课程根本不解释bind parameters。将文字值写入SQL语句本身对于人类直接使用数据库时的即席查询非常方便,但这只是程序中的错误方法。程序应始终使用绑定参数(性能极少的例外)有效地保护程序100%不受SQL注入。问题是SQL教科书不能这么说。

    即便如此,SQL也有健全的安全系统,允许您根据某些规则限制对表,视图,有时甚至是选定行的访问("行级安全性")。

  2. "可能的最小存储空间"

    抱歉,我不明白这个问题。

  3. 关于规范化。

    你是对的。规范化解决了一些问题(重复数据删除和防止无意的不一致),但打开了其他一些问题。即:

    • 如何轻松访问多个表中的数据。
    • 如何保持多个表的一致性。
    • 如何应对故意的"不一致"又名。历史(主数据变更)

    原则上,SQL应提供工具来补偿规范化带来的这些挑战。

    应使用SQL的连接和类似操作来访问许多表中的数据。 SQL不仅仅以1:1的方式存储和检索数据,它还提供工具(连接,子查询,集合操作......),将规范化数据转换为最适合特定任务的形式。这是在运行时故意完成的,因为事先不需要知道任务。另一方面,数据的性质被认为是静态的,因此以标准化的方式存储它是有效的。这是关系模型和SQL的一个非常重要的关键概念:数据的 nature 不会发生变化,因此它应该是持久性的。您如何使用这些数据的方式差异很大,并且经常会随着时间而变化 - 因此必须动态完成。这当然是一项非常常规的任务,因此有一个可靠的工具使其变得容易。我们将此工具称为SQL;)DRY规则可以通过使用视图或CTEs来完成,但两者都可能会损害性能,因为实现已经针对该优化进行了优化(我公开批评的事情!)。

    在许多表中保持数据一致主要是在约束的帮助下完成的。

    处理预期的"不一致" (历史)终于由SQL:2011覆盖:这将允许" AS OF"查询并提供维护时间一致性的工具(例如,一行的有效性可能与另一行的有效性不重叠)。可以说,用40年左右的时间来提出解决方案是非常糟糕的。我甚至都不知道这种情况何时会普遍存在!

    我认为这部分对于每个系统都是如此:"人们很难在失败的情况下理解 " (我的重点)。但是,我认为您可能意味着很难调查问题,因为所需的数据可能分散在多个表中。 SQL的答案是:VIEW基本上只是存储的查询。但是,根据数据库带,VIEW可能会引入性能问题。但是,这是一些数据库频段的限制,而不是SQL或关系模型的限制。

  4. 保持历史

    我已经在上面提到过(SQL:2011)。

    对于每个希望保留历史记录的系统,情况也是如此:"导致表格规模呈指数级增长。"虽然我说它不断增长"不是"以指数方式"。

    应对它的工具是触发器或ORM。如果你想确保没有人进行过破坏性的更新"你可以撤销该表的UPDATE权限(并且DELETE也在保存方面)。

  5. "更喜欢数据丢失而导致失去一致性:"

    我发现这是一个有趣的观点。但是,SQL的答案是,您首先要努力避免将错误的数据输入系统。主要通过使用适当的模式,约束+ ACID。通过这种方式,您的陈述在某种程度上是正确的:而不是接受不一致的数据被拒绝(这与丢失的东西不同!)。因此,您必须在某人输入被拒绝的数据时处理错误,而不是稍后当您尝试解决不一致时,因为您首先接受了错误的数据。是的,这是关系模型和SQL的哲学!

    缺乏人类可读性显然取决于您的背景。但是,我说,使用SQL的正确能力非常好。在这里,我还想引用最初的IBM论文SEQUEL(当时它是它的真实名称):

      

    SEQUEL旨在为专业程序员和不常见的数据库用户提供数据库子语言。

    在我的观察中,这是绝对正确的:我最近有一个教授SQL来支持员工的任务,以便他们可以直接在数据库中调查案例。他们不是程序员,但很快就理解SQL。而且我认为在这里踢你的"人类"参数:他们遇到的问题是导航一个由数百个表组成的真实世界关系模型。但是,通过要求开发人员为涉及多个表的一些常见任务提供视图,很快就解决了这个问题。加入这些观点就不再有问题了。

    对于关系思维,你需要一个不同的思维模式,你需要一个不同的中间集来进行函数式编程。这不是好事或坏事 - 但对你来说可能并不常见。一旦你经常使用它,你就会习惯它。

  6. 对象/关系阻抗不匹配

    我认为这个话题不需要长时间的讨论:是的它存在,是的,有些工具可以用某种方式处理它。我已经在我的文章中提出了过度使用的观点。

  7. 数据结构更改

    我认为这主要是由于对关系模型的理解不足。比较上面:"数据的性质"

    这也是一个讨论得很好的论点:架构与"架构较少"。选择你的味道。 " Schema less"通常只是意味着"没有提供架构管理工具"然而,你必须应对这样一个事实,即我们有时想要为现有实体添加更多属性。 RDBMS为此提供了工具:新列可以为空或具有默认值。可以使用CREATE AS SELECT进行更激烈的更改,例如将一个属性移动到额外的表(例如1:n)。您甚至可以提供仍然提供数据的兼容性视图(就像移动的属性仍将存储在表中一样)。一旦您更改了架构,您的应用程序就可以依赖它的约束(例如列的存在或约束的有效性)。数据库可以以非常可靠的方式为您做很多事情。你不再需要关心你的应用程序了。

    您没有提到的一个论点是,这些架构更改通常涉及停机时间。这对过去来说确实如此,在某种程度上也是如此。例如。 MySQL最近在5.6中引入了在线ALTER TABLE。但是,这通常是一个实现限制,而不是与关系模型或SQL本身相关的问题。即使是一些更复杂的更改(例如将属性移动到另一个表)也可以在线完成并仔细规划(我已经完成了一个昂贵的数据库,提供了所需的所有工具)。通常,它是关于将迁移代码保留在应用程序之外并使用它来处理数据库。迁移后,您既不应该在数据库中也不应该在应用程序代码中具有迁移工件。当然,有些情况下停机是不可避免的(我认为;)。

  8. "混合存储逻辑和应用程序逻辑"

    SQL实际上完全相反:SQL完全取消了存储层。

    没有人强迫您使用存储过程。我个人也认为存储过程被过度使用,主要是因为存储过程存储在数据库中,因此可以由可能无法访问其他源代码的数据库管理员进行更改(优化)。换句话说:我认为这通常是出于绝望。

    第二个论点当然是再次过度使用ORM以及禁止在应用程序中使用真实SQL的策略。

答案 1 :(得分:3)

  1. SQL本质上是不安全的。不,不是。使用参数化语句。
  2. SQL似乎是针对可能的最小存储大小而制作的。这只是通过规范化减少重复的次要结果。规范化的好处是更小的更新和简化的约束检查。
  3. SQL强制所有内容都适合二维关系模型。这有点适用于DML(查询)但不适用于DDL(数据定义),这更为重要。现代SQL无论如何都通过像postgres json这样的技术打破了2D组合。
  4. SQL不维护历史记录:这完全是假的。通过触发器维护历史记录是微不足道的,但这绝对不应该是默认值。数据时间旅行非常耗费空间,但是,如果必须这样做,由于规范化,SQL和noSQL会更容易和更小,并且如果您需要正式的历史约束检查,则能够在时间上运行RI。
  5. SQL似乎更倾向于数据丢失而导致一致性丢失这样做并不顺从。除了从备份还原之外,还有很多方法可以恢复一致性。
  6. 在完整堆栈Web应用程序中三次。这是真的。但是你想在错误的地方减肥。 SQL是一种非常正式的数据定义。考虑放弃ORM并切断客户端。
  7. 数据结构更改似乎被视为一致性问题:这只是错误的。你可以留下一个新的记录默认值null,这在大多数sql实现中都不会导致记录被重写(ALTER TABLE foo ADD f TEXT;是O(1))。另请注意,postgres结构更改是事务性的,可以回滚。
  8. 混合存储逻辑和应用程序逻辑:这是一个非常愚蠢的论点。这类似于说不应该用数据结构编译C二进制文件。没有“存储逻辑,业务逻辑或应用程序逻辑”这样的东西。 只是逻辑。将逻辑更紧密地耦合到数据结构极大地提高了性能,并使得更容易管理功能依赖性。我永远不会理解为什么程序员认为让数据库通过协议序列化记录,将其移动到另一个进程(甚至另一个服务器)上的应用程序并通过反序列化而不是让数据库将其写回数据库“更好”做吧。