我最近阅读了很多文章,从两个方面描述了SQL和NoSQL,例如http://use-the-index-luke.com/blog/2013-04/whats-left-of-nosql.这些文章经常涉及ACID和可伸缩性等主题.但是,我通常在SQL中遇到的一些问题似乎很少在这些文章中提及,我想知道为什么,以及这是否与我不完全理解SQL有关.如果有人能够启发我,至少部分是通过以下一项或多项,我将非常感激.
我的SQL问题:
SQL本质上是不安全的:SQL是一种用于插入的语言,没有任何方法来阻止代码而不是数据的插入.防止插入的唯一方法是使用它将SQL与应用程序完全隔离.为什么SQL本身还没有解决这个问题?
SQL似乎是针对其中包含的数据可能的最小存储大小而制作的.虽然这仍然对大量数据有很大意义,但它不再适用于较小的数据库,或者它是什么?
SQL强制所有内容都适合二维关系模型,特定关系表用于执行其他维度.对我来说,这有两个问题:
数据的一致性完全依赖于关系表
在失败的情况下,人类很难理解数据
SQL没有维护历史记录,因为默认情况下它会进行破坏性更新:当然有各种方法来创建历史记录,但这需要使用额外的表格和使用时间戳来自定义编写的东西,或者为此创建新的记录每一次变化,都会导致表格规模呈指数级增长.
SQL似乎更倾向于丢失数据丢失:如果发生错误或丢失一致性,将情境恢复到一致状态的唯一方法是使用备份,这意味着最新的更改将被销毁.这部分是因为缺乏历史(见4),而且由于缺乏人类可读性,没有真正的方法让人类尝试纠正错误.
特别是在Web环境中,SQL的使用通常意味着通常不止一次创建模型.在普通(简单)PHP Web应用程序中两次:一次在PHP中,一次在SQL中.在完整堆栈Web应用程序中三次:一次在客户端应用程序中,一次在中间件中,一次在SQL数据库中(如果没有使用ORM).由于编程语言不同,以及它们之间的类型差异,这意味着这些模型之间存在很多可能的冲突.我知道像ActiveRecord和Django这样的ORM解决了这些问题中的至少一部分,但是由于SQL表包含VARCHAR(25)并且没有使用任何语言(JavaScript,Ruby,PHP),您还需要做额外的工作量. ,Perl,Python等)知道那种构造,是巨大的.
数据结构更改似乎被视为一致性问题:如果数据结构中的某些内容发生更改,表更改将应用于该表中的每个现有记录,即使记录最初没有该字段且是否有意义该记录有该字段.一组这些更改会导致自动迁移,这会增加另一层可能出现的问题,尤其是在一致性方面.
混合存储逻辑和应用程序逻辑:SQL似乎急于将应用程序逻辑的一部分吞噬为存储过程(CouchDB也通过视图执行此操作).虽然我知道对于某些类型的操作,您需要服务器端和非常严格控制的过程,但我不明白为什么它们存储在数据库中并作为存储引擎的一部分,而不是作为应用程序的一部分(中间件).
我知道(但不是很熟悉)像PostgreSQL Hstore这样的东西,但是我并没有完全看到它如何解决上面提到的问题.感谢您的任何见解!
SQL固有的不安全吗?
我认为你指的是SQL Injections,它是最危险的安全漏洞之一.
但是,SQL注入主要是教育问题,因为大多数教科书和课程根本不解释绑定参数.当人类直接使用数据库时,将文字值写入SQL语句本身对于即席查询很方便,但这只是程序中的错误方式.程序应始终使用绑定参数(性能极少的例外)有效地保护程序100%不受SQL注入.问题是SQL教科书没有这么说.
即便如此,SQL也有健全的安全系统,允许您根据某些规则限制对表,视图甚至选定行的访问("行级安全性").
"可能的最小存储空间"
对不起,我没有得到那个问题.
关于规范化.
你是对的.规范化解决了一些问题(重复数据删除和防止无意的不一致),但打开了其他一些问题.即:
如何轻松访问许多表中的数据.
如何在许多表中保持一致性.
如何应对故意的"不一致"又名.历史(主数据变更)
原则上,SQL应提供工具来补偿规范化带来的这些挑战.
应该使用SQL的连接和类似操作来访问许多表中的数据.SQL不仅仅以1:1的方式存储和检索数据,它还提供工具(连接,子查询,集合操作......),将规范化数据转换为最适合特定任务的形式.这是在运行时故意完成的,因为事先不需要知道任务.另一方面,数据的性质被认为是静态的,因此以标准化的方式存储它是有效的.这是关系模型和SQL的一个非常重要的关键概念:数据的性质不会改变,因此它应该是持久的方式.您如何使用这些数据的方式差别很大,并且经常会随着时间而变化 - 因此必须动态完成.这当然是一项非常常规的任务,因此有一个可靠的工具使其变得容易.我们称这个工具为SQL;)DRY规则可以通过使用视图或CTE来完成,但两者都可能损害性能,因为实现没有很好地优化(我公开批评的东西!).
在许多表中保持数据一致主要是在约束的帮助下完成的.
SQL:2011最终涵盖了处理预期的"不一致性"(历史):这将允许"AS OF"查询并提供维护时间一致性的工具(例如,一行的有效性可能与另一行的有效性不重叠).可以说,用40年左右的时间来提出解决方案是非常糟糕的.我甚至都不知道这种情况何时会普遍存在!
我认为这一部分对于每个系统都是如此:"人们很难在失败的情况下理解数据"(我的重点).但是,我认为您可能意味着很难调查问题,因为所需的数据可能分散在多个表中.SQL的答案是:VIEW基本上只是存储的查询.但是,根据数据库带,VIEW可能会引入性能问题.但是,这是一些数据库带的限制,而不是SQL或关系模型的限制.
保持历史
我已经在上面提到过(SQL:2011).
对于每个希望保留历史记录的系统,情况也是如此:"导致表格规模呈指数级增长".虽然我说它"不断增长"而不是"指数级".
应对它的工具是触发器或ORM.如果你想确保没有人进行"破坏性更新",你可以撤销该表的UPDATE权限(并且还要保留在保存端).
"更喜欢数据丢失而失去一致性:"
我发现这是一个有趣的观点.但是,SQL的答案是,您首先要努力避免将错误的数据输入系统.主要通过使用适当的模式,约束+ ACID.通过这种方式,您的陈述在某种程度上是正确的:拒绝接受不一致的数据(这与丢失的东西不同!).因此,您必须在某人输入被拒绝的数据时处理错误,而不是稍后当您尝试解决不一致时,因为您首先接受了错误的数据.所以是的,这就是关系模型和SQL的哲学!
人类可读性的缺乏显然取决于你的背景.但是,我会说,使用SQL的正确能力非常好.在这里,我还想引用最初的关于SEQUEL的 IBM论文(当时它是它的真实名称):
SEQUEL旨在作为专业程序员和较不频繁的数据库用户的数据库子语言.
在我的观察中,这是绝对正确的:我最近有一个教授SQL来支持员工的任务,以便他们可以直接在数据库中调查案例.他们不是程序员,但很快就理解SQL.我认为这里踢出你的"人类"论点:他们遇到的问题是导航一个由数百个表组成的真实世界关系模型.但是,通过要求开发人员为涉及多个表的一些常见任务提供视图,很快就解决了这个问题.加入这些观点就不再是问题了.
对于关系思维,你需要一个不同的思维模式,你需要一个不同的中间设置到函数式编程.这不是好事或坏事 - 但对你来说可能并不常见.一旦你经常使用它,你就会习惯它.
对象/关系阻抗不匹配
我认为这个话题不需要长时间的讨论:是的,它存在,是的,有一些工具以某种方式应对它.我已经在我的文章中提出了过度使用的观点.
数据结构变化
我认为这主要是由于对关系模型的理解不足.比较上面:"数据的性质"
这也是一个讨论得很好的论点:架构与"架构较少".选择你的味道."Schema less"通常仅仅意味着"不提供模式管理工具",但是你必须应对我们有时想要向现有实体添加更多属性的事实.RDBMS为此提供了工具:新列可以为空或具有默认值.可以使用CREATE AS SELECT进行更激烈的更改,例如将一个属性移动到额外的表(例如1:n).您甚至可以提供仍然提供数据的兼容性视图(就像移动的属性仍将存储在表中一样).一旦更改了模式,您的应用程序就可以依赖它的约束(例如列的存在或约束的有效性).这是数据库可以非常可靠地为您做的很多事情.你不再需要关心你的应用程序了.
您没有提到的一个论点是,这些架构更改通常涉及停机时间.这对过去来说确实如此,在某种程度上也是如此.例如,MySQL最近在5.6中引入了在线ALTER TABLE.但是,这通常是一个实现限制,而不是与关系模型或SQL本质上相关的问题.即使是一些更复杂的更改(例如将属性移动到另一个表)也可以在线完成并仔细计划(我已经完成了一个昂贵的数据库,提供了所需的所有工具).通常,它是关于将迁移代码保留在应用程序之外并使用它来处理数据库.迁移后,您既不应该在数据库中也不应该在应用程序代码中具有迁移工件.当然,有些情况下停机是不可避免的(我认为;).
"混合存储逻辑和应用程序逻辑"
SQL实际上完全相反:SQL完全抽象出存储层.
没有人强迫您使用存储过程.我个人也认为存储过程被过度使用,主要是因为存储过程存储在数据库中,因此可以由可能无法访问其他源代码的数据库管理员进行更改(优化).换句话说:我认为这通常是出于绝望.
第二个参数当然是再次过度使用ORM以及不允许在应用程序中使用真正SQL的策略.