为什么不爱SQL?
最近我听说SQL是一种糟糕的语言,似乎太阳下的每个框架都预先打包了一个数据库抽象层。
根据我的经验,SQL通常是更简单,更通用,更方便编程的数据input和输出pipe理方式。 我所使用的每个抽象层似乎是一个明显有限的方法,没有真正的好处。
是什么让SQL如此糟糕,为什么数据库抽象层有价值?
这部分是主观的。 所以这是我的看法:
SQL具有伪自然语言风格 。 发明人相信,他们可以像英语一样创build一种语言,数据库查询将非常简单。 一个可怕的错误。 SQL很难理解,除非在微不足道的情况下。
SQL是声明式的。 你不能告诉数据库应该怎么做,只是你想要的结果。 这将是完美的,非常强大 – 如果你不必关心性能。 所以最后你会写SQL–读执行计划 – 改写SQL来影响执行计划,你想知道为什么你不能自己写执行计划 。
声明性语言的另一个问题是有些问题更容易解决。 所以你要么写另一种语言(你需要标准的SQL,可能是数据访问层),要么使用供应商特定的语言扩展,比如编写存储过程等等。 这样做,你可能会发现,你使用的是你所见过的最糟糕的语言之一 – 因为它从来没有被devise成一个命令式的语言。
SQL 非常古老 。 SQL已经标准化,但已经太迟了,许多供应商已经开发了他们的语言扩展。 所以SQL以数十个方言结束。 这就是为什么应用程序不可移植,并有一个原因有一个数据库抽象层。
但事实确实如此 – 没有可行的select。 所以我们都将在未来几年使用SQL。
除了所说的一切之外, 一个技术并不一定是坏的,所以抽象层是有价值的 。
如果你正在做一个非常简单的脚本或应用程序,你可以随时随地在你的代码中混合使用SQL调用。 但是,如果你正在做一个复杂的系统,在单独的模块中隔离数据库调用是一个好的做法,所以它是隔离你的SQL代码。 它提高了您的代码的可读性,可维护性和可testing性。 它使您可以快速调整系统以适应数据库模型的变化,而不会破坏所有的高级内容等。
SQL是伟大的。 它上面的抽象层使得它更大!
抽象层的一点是,SQL实现往往或多或less互不兼容,因为标准稍微模糊,也因为大多数供应商在那里添加了自己的(非标准)附加组件。 也就是说,针对MySQL数据库编写的SQL可能与Oracle数据库无法相当类似,即使它“应该”也是如此。
不过,我同意SQL比大多数抽象层更好。 这不是SQL的错误,它被用于它不是为了devise的东西。
SQL从几个来源变得糟糕透顶:
- 对任何东西都不感到舒服的程序员,除了命令式的语言。
- 必须每天处理许多不兼容的基于SQL的产品的顾问
- 非关系型数据库供应商试图打破市场上关系数据库供应商的束缚
- 像Chris Date这样的关系数据库专家认为当前SQL的实现不足
如果你坚持一个DBMS产品,那么我绝对同意SQL DB比其竞争对手更通用,质量更高,至less在你遇到模型中固有的可扩展性障碍之前。 但是,你真的想写下一个Twitter,还是只是想保持一些会计数据的组织和一致?
对SQL的批评常常是批评RDBMS的一个原因。 关于RDBMS的批评者似乎不了解的是,他们很好地解决了一大类计算问题,他们在这里让我们的生活更轻松,更难。
如果他们认真地批评SQL本身,他们会回头看看Tutorial D和Dataphor。
这不是很可怕。 当一个新的“范式”出现时,这个行业的一个不幸的趋势就是摒弃了以前的可靠技术。 在这一天结束的时候,这些框架非常可能使用SQL来与数据库进行通信,那么它怎么会这么糟糕呢? 也就是说,拥有“标准”抽象层意味着开发人员可以专注于应用程序代码而不是SQL代码。 如果没有这样一个标准的图层,你可能会在每次开发一个系统的时候写一个轻量级的graphics,这是一种浪费。
SQL被devise用于pipe理和查询基于SET的数据。 它经常被用来做更多的事情,边缘案件有时会导致挫败感。
SQL的实际使用可能会受基础数据库devise的影响,因为SQL可能不是问题,但是devise可能 – 而且当您抛弃与不良devise相关的遗留代码时,变更对冲突的影响更大且成本更高没有人喜欢回去“修补”那些“工作”和达到目标的东西)
木匠可以用锤子敲钉子,用锯子锯木材,用飞机光滑的木板。 有可能使用锤子和飞机“看到”,但是这令人沮丧。
我不会说这太可怕了 这是不适合的一些任务。 例如:你不能用SQL编写好的程序代码。 我曾经被迫使用SQL进行集合操作。 我花了整整一个周末才弄明白这一点。
SQL是为关系代数devise的 – 这就是应该使用的地方。
最近我听说SQL是一种糟糕的语言,似乎太阳下的每个框架都预先打包了一个数据库抽象层。
请注意,这些层只是将自己的东西转换成SQL
。 对于大多数数据库供应商来说, SQL
是与引擎进行通信的唯一方式。
根据我的经验,SQL通常是更简单,更通用,更方便编程的数据input和输出pipe理方式。 我所使用的每个抽象层似乎是一个明显有限的方法,没有真正的好处。
…我之前刚刚描述的原因
数据库层不添加任何东西,他们只是限制你。 他们使查询更加简单,但从未更有效率。
根据定义,数据库层中没有不在SQL
中的任何东西。
是什么让
SQL
如此糟糕,为什么数据库抽象层有价值?
SQL
是一个很好的语言,但是,它需要一些脑力的工作。
从理论上讲, SQL
是声明式的,即你声明你想得到的东西,并且引擎以最快的方式提供它。
在实践中,有许多方法来制定正确的查询(即返回正确结果的查询)。
优化器能够用一些预定义的algorithm(是的,它们是多个)构buildLego城堡,但是它们不能制造新的algorithm。 它仍然需要一个SQL
开发人员来协助他们。
但是,有些人希望优化器能够产生“最好的可能计划”,而不是“给定实现SQL
引擎的最佳计划”。
众所周知,当电脑程序不符合人们的期望时,这个程序就会被指责,而不是期望。
然而,在大多数情况下,重新构build查询可能会产生一个最好的计划。 有些任务是不可能的,但是随着对SQL
的新的和日益增长的改进,这些例子的数量越来越less。
但是,如果供应商提供了一些底层的访问权限,比如“获取索引范围”,“通过rowid
获得一行”等等,就好像C
编译器让你能够将程序集embedded到语言。
我最近在我的博客上写了一篇文章:
- 在SQL中双重思考
我是一个巨大的ORM倡导者,我仍然相信SQL是非常有用的,尽pipe它可以做任何可怕的事情(就像其他事情一样)。 。
我将SQL视为一种超级高效的语言,它没有将代码重用或可维护性/重构作为优先级。
所以闪电处理是重中之重。 这是可以接受的。 你只需要意识到这一点,这对我来说是相当可观的。
从美学的angular度来看,作为一种语言,我觉得它缺less一些东西,因为它没有面向对象的概念等等 – 对我来说,这感觉就像是一个非常老派的程序代码。 但是,做某些事情是最快捷的方式,这是一个强大的利基!
我会说,框架中包含的数据库抽象层是一件好事,因为它解决了两个非常重要的问题:
-
它保持代码不同。 通过将SQL放入另外一个通常非常简单的层中,只需要做一些基本的查询和结果切换(以标准化方式),就可以让应用程序摆脱SQL的混乱。 这与Web开发人员(应该)将CSS和Javascript放在单独的文件中的原因是一样的。 如果你能避免, 不要混用你的语言 。
-
许多程序员在使用SQL时显然不好。 无论出于何种原因,大量的开发人员(尤其是Web开发人员)似乎在使用SQL或RDBMSes方面非常糟糕。 他们把数据库(和扩展的SQL)当作肮脏的小中间商,他们必须经历数据。 这导致极其糟糕的数据库没有索引,以可疑的方式堆放在表顶部的表格,以及写得很差的查询。 或者更糟的是,他们试图过于笼统(专家系统,任何人?),并且不能以任何有意义的方式合理地关联数据。
不幸的是,有时候,有人试图解决问题的方式和工具,无论是由于无知,固执还是其他一些特质,都是彼此直接对立的,好运气试图说服他们。 因此,除了仅仅是一个良好的实践之外,我认为数据库抽象层是一种安全networking,因为它不仅使得SQL远离了可怜的开发人员的眼睛,而且使得它们的代码更容易重构,因为所有的查询都在一个地方。
对于某些types的任务,SQL非常适用,特别是操作和检索数据集 。
但是,SQL缺less(或仅部分实现)几个用于pipe理变更和复杂性的重要工具:
-
封装 :SQL的封装机制是粗糙的。 当你编写SQL代码时,你必须知道你的数据实现的一切。 这限制了您可以实现的抽象的数量。
-
多态性 :如果你想在不同的表上执行相同的操作,你必须写两次代码。 (人们可以用想象的方式来缓解这种观点。)
-
可见性控制 :没有标准的SQL机制可以将代码彼此隐藏起来,也可以将它们分组为逻辑单元,因此即使不合需要,也可以访问每个表,程序等。
-
模块化和版本控制
最后,在SQL中手动编码CRUD操作(并编写代码以将其连接到应用程序的其余部分)是重复的,并且容易出错。
现代抽象层提供所有这些function,并允许我们在最有效的地方使用SQL,同时隐藏破坏性重复的实现细节。 它提供了一些工具来帮助克服在面向对象软件开发中使数据访问复杂化的对象 – 关系阻抗不匹配 。
SQL基于集合论,而大多数高级语言是面向对象的。 对象程序员通常喜欢在对象中思考,并且必须进行思维转换才能使用基于集合的工具来存储对象。 一般来说,对于OO程序员来说,只需要用自己select的语言来切割代码,并在应用程序代码中执行诸如object.save或object.delete而不必编写sql查询并调用数据库来实现相同的结果。
当然,有时对于复杂的事情,SQL更容易使用,效率更高,所以最好能够处理这两种types的技术。
IMO,我看到人们用SQL的问题与关系devise和SQL语言本身无关。 它与build模数据层的原则相关,在许多方面与build模业务层或接口有着根本的不同。 在表示层build模的错误通常比在使用数据库的多个应用程序的数据层更容易纠正。 这些问题与在SOAdevise中build模服务层时遇到的问题相同,您必须考虑服务的当前使用者以及input和输出合同。
SQL被devise为与关系数据库模型交互。 还有一些其他的数据模型已经存在了一段时间,但是无论使用何种理论模型,数据层的devise原则都是正确存在的,因此,开发人员通常在SQL中遇到的困难通常与试图强加一个非关系数据模型到关系数据库产品上。
首先,它们使得使用参数化查询变得微不足道,从而保护您免受SQL注入攻击。 从这个angular度来看,使用原始SQL更危险,也就是说,从安全angular度来看更容易出错。 他们也经常提出一个面向对象的angular度来看待你的数据库,让你不必做这个翻译。
听到很多最近? 我希望你不要把这个与NoSql运动混为一谈。 据我所知,主要是一些谁使用高可伸缩性Web应用程序的NoSql,似乎忘记了SQL是一个非“高可伸缩性的Web应用程序”的情况下有效的工具。
抽象层业务仅仅是要区分面向对象的代码和基于表的设置之类的代码,如SQL喜欢说话。 通常这会导致在两者之间写入大量的锅炉板和沉闷的转换代码。 ORM自动化这一点,从而为业务目标人员节省时间。
对于有经验的SQL程序员来说,糟糕的一面是
- 赘言
- 正如很多人在这里所说的,SQL是声明性的,这意味着优化不是直接的 。 这就像赛车比赛一样。
- 试图解决所有可能的方言的框架,不支持其中任何一个的快捷方式
- 没有简单的版本控制。
对于其他人来说,原因是这样的
- 有些程序员对SQL不好。 可能是因为SQL使用集合运行,而编程语言在对象或function范式中工作。 组合(联盟,产品,相交)的思考是一些人所不具备的习惯。
- 有些操作不是自解释性的,即首先不清楚在哪里和过滤不同的集合。
- 方言太多了
SQL框架的主要目标是减less你的input。 他们不知何故,但往往只为非常简单的查询。 如果你尝试做一些复杂的事情,你必须使用string并input很多。 尝试处理所有事情的框架,像SQL Alchemy,变得太庞大,就像另一种编程语言。
[更新于26.06.10]最近我使用Django ORM模块 。 这是我见过的唯一有价值的SQL框架。 而这个使得很多东西的工作。 但是复杂的总量有点难度。
SQL不是一个可怕的语言,有时候和其他人玩得不太好。
例如,如果您有一个系统想要将所有实体表示为某种OO语言或另一种语言中的对象,那么将其与SQL结合,而不使用任何抽象层可能会变得相当麻烦。 将复杂的SQL查询映射到面向对象的世界上并不容易。 为了缓解这些世界之间的紧张关系,插入了额外的抽象层(例如OR映射器)。
SQL是数据操作的一个非常好的语言。 从开发人员的angular度来看,我不喜欢的是在编译时更改数据库不会破坏您的代码…所以我使用抽象,以性能为代价添加此function,可能expression的SQL语言,因为在大多数应用程序中,你不需要SQL所有的东西。
SQL被讨厌的另一个原因是关系数据库。
CAP定理变得stream行:
你可以从共享数据系统中获得什么目标?
- 强一致性:即使在更新的情况下,所有客户端也能看到相同的视图
- 高可用性:即使在出现故障的情况下,所有客户端也可以find数据的一些副本
- 分区容错(Partition-tolerance):系统属性即使在系统被分区时也是如此
该定理指出,您可以同时只有三个CAP属性中的两个
关系数据库地址强一致性和分区容差。
所以越来越多的人意识到关系型数据库并不是最重要的,越来越多的人开始拒绝它,以获得高可用性,因为高可用性使得横向扩展更加容易。 因为我们已经达到了摩尔定律的极限 ,所以横向缩放比较受欢迎,所以最好的扩展方法是增加更多的机器。
如果关系数据库被拒绝,SQL也被拒绝。
SQL有许多缺陷,正如其他一些海报所指出的那样。 尽pipe如此,我更喜欢使用SQL来替代人们提供的许多工具,因为“简化”通常比他们应该简化的东西更为复杂。
我的理论是,SQL是由一群象牙塔蓝色的滑雪者发明的。 整个非程序结构。 听起来不错:告诉我你想要什么,而不是你想怎么做。 但是在实践中,仅仅给出步骤往往更容易。 通常这似乎是试图通过描述汽车在完成时应该如何执行来给出汽车维护说明。 是的,你可以说,“我希望汽车每加仑再跑30英里,用这种嗡嗡的声音跑这个……嗯…等等,”但是对于每个人来说,只是说,“更换火花塞”? 而且,即使在确定如何以非程序化的术语expression复杂的查询时,数据库引擎通常也会出现非常低效的执行计划。 我想通过添加标准化的方式来告诉它哪个表首先要读取哪个表,以及使用哪个索引,SQL会得到很大的改善。
而空值的处理让我疯狂! 是的,从理论上讲,当有人说:“嘿,如果null表示未知数,那么给一个已知值添加一个未知值应该给出一个未知值。毕竟,根据定义,我们不知道未知值是什么“。 理论上,绝对正确。 在实践中,如果我们有10,000个客户,并且我们知道9999美元到底需要多less钱,但是对最后一个欠款有一些疑问,pipe理层说:“我们的总应收账款是多less?”是的,math上是正确的答案是“我不知道”。 但是实际的答案是“我们计算了$ 4,327,287.42 $ 4,但是有一个帐户是有问题的,所以这个数字是不准确的”。 我相信pipe理层如果不是一个确定的数字,而不是一个空洞的目光,宁可接近。 但是SQL坚持使用这种非常原始的方法,所以每一个操作都需要添加额外的代码来检查空值并处理它们。
尽pipe如此,我仍然宁愿使用SQL,而不是在SQL之上构build的某个层,这只是创build了另一整套我需要学习的东西,然后我必须知道最终这将被转换为SQL,有时候我可以信任它来正确有效地进行翻译,但是当事情变得复杂的时候我不能,所以现在我必须知道额外的层,我仍然需要知道SQL,而且我必须知道它将如何翻译我可以欺骗层欺骗SQL做正确的事情。 Arggh。
•每个供应商都会扩展SQL语法以满足他们的需求。 所以除非你做相当简单的事情,否则你的SQL代码是不可移植的。
•SQL的语法不正交; 例如, select, insert, update,
和delete
语句都有完全不同的语法结构。
我同意你的观点,但是要回答你的问题,让SQL变得如此“糟糕”的一件事是,数据库供应商(Sql Server,Oracle等)之间缺乏对T-SQL的完全标准化,这使得SQL代码不太可能完全便携。 数据库抽象层解决了这个问题,虽然性能成本(有时非常严重)。
用纯SQL生活确实是一个维护的地狱。 对我来说,ORM的最大好处就是能够安全地重构代码而不需要繁琐的“数据库重构”过程。 有很好的面向对象语言的unit testing框架和重构工具,但是我还需要看到,例如,Resharper的SQL对象。
尽pipe如此,所有的DAL在后台都有SQL,而且您仍然需要了解它以了解数据库正在发生的情况,但每天使用良好抽象层的工作变得更加容易。
如果你没有太多的使用SQL,我认为主要的问题是缺乏好的开发工具。
如果你有很多SQL的经验,你会在某种程度上由于缺乏对执行计划的控制而感到沮丧。 这是SQL向供应商指定的一个固有问题。 我认为SQL需要成为一个更强大的语言来真正利用底层技术(这是非常强大的)。
快点,给我写一个SQL来分析在MySQL,Oracle,MSSQL,PostgreSQL和DB2中工作的数据集。
哦,对,标准的SQL没有定义任何运算符来限制返回结果的数量和从哪一行开始。
对SQL没有爱,因为SQL在语法,语义和当前使用方面都不好。 我会解释一下:
- 它的语法是一个cobol弹片,所有的cobol批评适用于这里(以较小的程度,公平)。 试图成为自然语言,而实际上并没有试图解释自然语言创build语义语法(它是DROP TABLE或DROP,UPDATE TABLE,UPDATE或UPDATE IN,DELETE或DELETE FROM …)以及像SELECT一样的语法混乱(有多less页它填充?)
- 语义也有很大的缺陷,Date详细地解释了它,但是足以注意到三值布尔逻辑并不真正适合一个关系代数,其中一行只能是或不是表的一部分
- 有一种编程语言作为数据库的主要(往往是唯一的)接口被certificate是一个非常糟糕的select,它创造了一种新的安全缺陷
我同意这里的大部分post,关于SQL效用的争论大多是主观的,但是我认为在您的业务需求的性质上更主观。
像Stefan Steinegger指出的那样,声明性语言对于指定你想要的而不是你想要做什么是很好的。 这意味着,从高级angular度来看,您的SQL的各种实现是相当不错的:也就是说,如果您只想获取一些数据而没有其他问题,则可以通过编写相对简单的查询来满足自己的需求,并selectSQL的实现这是适合你的。
如果你的工作水平要低得多,而且你需要自己去优化,那么这就远非理想了。 使用进一步的抽象层可以提供帮助,但是如果您真正想要做的是指定优化查询等的方法,那么在尝试优化时添加一个中间人是有点不直观的。
我使用SQL的最大问题就像其他“标准化”语言一样,真正的标准很less。 我几乎更喜欢学习Sybase和MySQL之间的一种全新的语言,所以我没有把这两个约定混为一谈。
我不喜欢SQL,但我也不想把它写成我正在开发的一部分。 DAL不是关于上市速度 – 实际上,我从来没有想过会有一个DAL实现比代码中的直接查询更快。 但是DAL的目标是抽象的 。 抽象是有代价的,在这里它需要更长的时间来实现。
虽然,好处是巨大的。 使用expression式类,强types数据集等来编写本地代码testing。我们使用“DAL”类,这是一个纯粹的DDD实现,使用C#中的generics。 所以我们有通用的存储库,工作单元实现(基于代码的事务)和逻辑分离。 我们可以做一些事情,比如嘲笑我们的数据集,并且在数据库实现之前进行实际开发。 在构build这样一个框架方面有一个前期成本,但业务逻辑再次成为展会的明星是非常好的。 我们现在将数据作为资源来使用,并且使用我们在代码中原生使用的语言进行处理。 这种方法的另一个好处是它提供了清晰的分离。 例如,我不再在网页中看到数据库查询。 是的,该页面需要数据。 是的,涉及数据库。 但是现在,无论我从哪里获取数据,都有一个(而且只有一个)地方可以进入代码并find它。 对小型项目来说可能不是什么大问题,但是当你在一个站点上有几百个页面或者桌面应用程序中有几十个窗口的时候,你真的可以欣赏它。
作为一名开发人员,我聘请了我使用自己的逻辑和分析技能来实现业务需求 – 而且我们的框架实现使我现在可以更高效。 作为经理,我宁愿让我的开发人员使用他们的逻辑和分析能力解决问题,而不是编写SQL。 事实上,我们可以build立一个完整的应用程序,使用数据库,而不必使用数据库,直到开发周期结束,这是一件非常美妙的事情。 这并不意味着对数据库专业人员的敲门砖。 有时候数据库的实现比解决scheme更复杂。 SQL(在我们的例子中,特别是Views和Stored Procs)是代码可以将数据作为服务使用的抽象点。 在数据和开发团队之间明显分离的商店中,这有助于消除等待数据库实施和更改的等待模式。 开发人员可以将焦点放在问题域上,而不必将鼠标hover在DBA上,而且DBA可以专注于正确的实现,而无需开发人员。
这里的许多post似乎都认为SQL是不好的,因为它没有“代码优化”function,并且你无法控制执行计划。
SQL引擎擅长的是为书面指令提供一个执行计划,针对数据和实际内容 。 如果您不介意编程方面的事情,您会看到数据比应用程序层之间传递的字节更多。
虽然SQL确实完成了这项工作,但肯定有问题…
- 它试图同时是高层次和低层次的抽象 ,这是…奇怪。 也许应该是两个或更多不同层次的标准。
- 作为一个标准是一个巨大的失败 。 当一个标准在所有事情中搅动,要求实施太多,要求太less,或出于某种原因不能达到激励供应商和执行者生产严格符合互操作性的完整实现的部分社会目标时,很多事情都会出错。 你当然不能说SQL已经做了这些。 看看其他标准,并注意标准的成败显然是达成有益合作的一个因素:
- RS-232 ( Bad , not nearly enough specified, even which pin transmits and which pin receives is optional, sheesh. You can comply but still achieve nothing. Chance of successful interop: really low until the IBM PC made a de-facto useful standard.)
- IEEE 754-1985 Floating Point ( Bad , overreach: not a single supercomputer or scientific workstation or RISC microprocessor ever adopted it, although eventually after 20 years we were able to implement it nicely in HW. At least the world eventually grew into it.)
- C89, C99, PCI, USB, Java ( Good , whether standard or spec, they succeeded in motivating strict compliance from almost everyone, and that compliance resulted in successful interoperation.)
- it failed to be selected for arguably the most important database in the world . While this is more of a datapoint than a reason, the fact that Google Bigtable is not SQL and not relational is kind of an anti-achievement for SQL.