为什么不喜欢 SQL?

最近我听说了很多关于 SQL 是一种糟糕的语言的事情,而且似乎每个框架都预先打包了一个资料库抽象层。

但根据我的经验,SQL 通常是管理数据输入和输出的更简单、更通用和更程序员友好的方法。我使用的每一种抽象层似乎都是一种明显有限的方法,没有任何实际效果。

是什么让 SQL 如此糟糕,为什么数据库抽象层如此有价值?

16432 次浏览

I wont say it's terrible. It's unsuitable for some tasks. For example: you can not write good procedural code with SQL. I was once forced to work with set manipulation with SQL. It took me a whole weekend to figure that out.

SQL 是为关系代数而设计的-这就是它应该被使用的地方。

SQL is not a terrible language, it just doesn't play too well with others sometimes.

If for example if you have a system that wants to represent all entities as objects in some OO language or another, then combining this with SQL without any kind of abstraction layer can become rather cumbersome. There's no easy way to map a complex SQL query onto the OO-world. To ease the tension between those worlds additional layers of abstraction are inserted (an OR-Mapper for example).

首先,它们使得使用参数化查询变得非常简单,可以保护您免受 SQL 注入攻击。从这个角度来看,使用原始 SQL 的风险更大,也就是说,从安全角度来看,更容易出错。它们还经常在数据库上显示一个面向对象的透视图,从而使您不必进行这种转换。

没那么可怕。当一个新的“范式”出现时,这个行业中的一个不幸的趋势就是废弃以前可靠的技术。最终,这些框架很可能使用 SQL 与数据库进行通信,那么它怎么会那么糟糕呢?也就是说,拥有一个“标准”抽象层意味着开发人员可以专注于应用程序代码,而不是 SQL 代码。如果没有这样一个标准层,那么每次开发系统时,您可能都会编写一个轻量级的层,这是一种浪费。

我同意你的观点,但是为了回答你的问题,一件让 SQL 如此“可怕”的事情是数据库供应商(SQL Server,Oracle 等)之间缺乏完全标准化的 T-SQL,这使得 SQL 代码不太可能完全可移植。数据库抽象层解决了这个问题,尽管需要付出性能代价(有时是非常严重的性能代价)。

抽象层的一个问题是,SQL 实现之间或多或少是不兼容的,因为标准稍微有些模棱两可,还因为大多数供应商都在那里添加了自己的(非标准的)附加内容。也就是说,为 MySQL 数据库编写的 SQL 可能与 Oracle 数据库不太相似ーー即使它“应该”这样做。

不过,我同意 SQL 比大多数抽象层都要好得多。SQL 的错不在于它被用于那些设计时没有考虑到的事情。

这在一定程度上是主观的,所以我的观点是:

SQL 有一个 pseudo-natural-language style。发明者相信他们可以创建一种像英语一样的语言,而且数据库查询将会非常简单。一个可怕的错误。SQL 非常难以理解,除了在一些琐碎的情况下。

SQL 是声明性的。你不能告诉数据库 怎么做它应该做的东西,只是你想要的结果。这将是完美的和非常强大的-如果你不必关心性能。因此,您最终编写了 SQL-读取执行计划-重新措辞 SQL 试图影响执行计划,并且您想知道为什么是 你不能自己写执行计划

声明性语言的另一个问题是,有些问题更容易用命令式方法解决。因此,您可以使用另一种语言编写它(您需要标准的 SQL,可能还需要一个数据访问层) ,或者使用特定于供应商的语言扩展,比如编写 存储程序等等。这样做你可能会发现你正在使用的是你所见过的最糟糕的语言之一——因为它从来没有被设计成一种命令式语言。

SQL 是 very old。SQL 已经标准化,但为时已晚,许多供应商已经开发了他们的语言扩展。所以 SQL 最后变成了几十种方言。这就是为什么应用程序是不可移植的,这也是使用 DB 抽象层的一个原因。

But it's true - there are no feasible alternatives. So we all will use SQL for the next few years.

SQL 是一种非常好的数据操作语言。从开发者的角度来看,我不喜欢的是改变数据库不会在编译时破坏你的代码... ... 所以我使用抽象来添加这个特性,代价是性能和 SQL 语言的表达能力,因为在大多数应用程序中,你不需要 SQL 所拥有的所有东西。

SQL 被讨厌的另一个原因是因为关系数据库。

CAP定理变得流行起来:

你想从一个 shared-data system?

  • 强一致性: 所有客户都看到相同的视图,即使在 更新
  • 高可用性: 所有客户都可以找到一些数据的副本,即使是在 the presence of failures
  • 分区公差: 即使在系统 是分区的

这个定理表明你总是可以 只有三个 CAP 中的两个 物业

关系数据库强烈的一致性和分区公差。

So more and more people realize that relational database is not the silver bullet, and more and more people begin to reject it in favor of high availability, because high availability makes horizontal scaling more easy. Horizontal scaling gain popularity because we have reached the 摩尔定律的极限, so the best way to scale is to add more machine.

如果关系数据库被拒绝,SQL 也会被拒绝。

SQL 用于基于 SET 的数据的管理和查询。它常常被用来做更多的事情,而边缘案例有时会导致挫折感。

SQL 的实际使用可能会受到基础数据库设计的严重影响,因此 SQL 可能不是问题所在,但是设计可能会受到影响——当你把与糟糕设计相关的遗留代码扔进去时,实现变更的影响会更大,成本也会更高(没有人喜欢回过头去“修复”那些“工作”并满足目标的东西)

木匠可以用锤子敲钉子,用锯子锯木材,用刨子刨光板。用锤子和飞机“锯”是可能的,但是该死的,这是令人沮丧的。

我同意这里的大多数文章,关于 SQL 实用性的争论主要是主观的,但我认为它更主观的性质是您的业务需求。

正如 Stefan Steinegger 指出的那样,声明性语言有助于指定您想要的东西,而不是您想要如何去做。这意味着从高层次的角度来看,你的各种 SQL 实现都是不错的: 也就是说,如果你只想得到一些数据,其他什么都不重要,你可以满足于编写相对简单的查询,并选择适合你的 SQL 实现。

如果你在一个“更低”的水平上工作,并且你需要自己优化所有这些,那么这远非理想。使用进一步的抽象层会有所帮助,但是如果您真正要做的是指定优化查询的方法等等,那么在尝试优化时添加一个中间人就有点违反直觉了。

我使用 SQL 遇到的最大问题就像其他“标准化”语言一样,真正的标准很少。我几乎更喜欢在 Sybase 和 MySQL 之间学习一门全新的语言,这样我就不会把这两个约定弄混了。

使用纯 SQL 可能真的是一个维护地狱。对我来说,ORM 的最大优点是能够安全地重构代码,而不需要冗长的“ DB 重构”过程。面向对象语言有很好的单元测试框架和重构工具,但是我还需要看到 Resharper 对应的 SQL。

尽管所有的 DALs 都在后台支持 SQL,但是你仍然需要了解它来理解你的数据库发生了什么,但是使用好的抽象层进行日常工作变得更加容易。

SQL gets badmouthed from several sources:

  • Programmers who are not comfortable with anything but an imperative language.
  • 每天必须处理许多不兼容的基于 SQL 的产品的顾问
  • 非关系型数据库供应商试图打破市场上关系数据库供应商的束缚
  • 像克里斯•戴特(chrisdate)这样的关系数据库专家认为当前的 SQL 实现不够充分

If you stick to one DBMS product, then I definitely agree that SQL DBs are more versatile and of higher quality than their competition, at least until you hit a scalability barrier intrinsic in the model. But are you really trying to write the next Twitter, or are you just trying to keep some accounting data organized and consistent?

对 SQL 的批评常常是对 RDBMS 的批评的代名词。RDBMS 的批评者似乎不明白的是,它们能很好地解决大量的计算问题,而且它们的目的是让我们的生活更轻松,而不是更困难。

如果他们真的想批评 SQL 本身,他们会支持像 TutorialD 和 Dataphor 这样的努力。

我是 ORM 的忠实拥护者,我仍然相信 SQL 是非常有用的,尽管可能会用它做一些糟糕的事情(就像其他任何事情一样)。.

我认为 SQL 是一种超级高效的语言,它没有代码重用或可维护性/重构作为优先级。

因此闪电般的快速处理是首要任务。这是可以接受的。你只需要注意权衡,这对我来说是相当重要的。

从美学的角度来看,作为一门语言,我觉得它缺少一些东西,因为它没有面向对象的概念等等——对我来说,它感觉像是非常老派的过程代码。但是这是做某些事情最快的方法,这是一个强大的利基!

除了刚才说的那些 一项技术不一定是坏的才能让抽象层变得有价值

If you're doing a very simple script or application, you can afford to mix SQL calls in your code wherever you like. However, if you're doing a complex system, isolating the database calls in separate module(s) is a good practice and so it is isolating your SQL code. It improves your code's readability, maintainability and testability. It allows you to quickly adapt your system to changes in the database model without breaking up all the high level stuff, etc.

SQL 是伟大的。它上面的抽象层使它更伟大!

如果您没有过多地使用 SQL,我认为主要的问题是缺乏好的开发工具。

If you have lots of experience with SQL, you will have, at one point or another, been frustrated by the lack of control over the execution plan. This is an inherent problem in the way SQL was specified to the vendors. I think SQL needs to become a more robust language to truly harness the underlying technology (which is very powerful).

我并不讨厌 SQL,但我也不想把它作为我正在开发的内容的一部分来编写。DAL 不是关于市场的速度——实际上,我从来没有想过会有一个 DAL 实现会比直接从代码查询更快。但是 DAL 的目标是 摘要。抽象是有代价的,在这里它将需要更长的时间来实现。

不过,这样做的好处是巨大的。围绕代码编写本机测试,使用表达式类、强类型数据集等。我们使用排序的“ DAL”,它是使用 C # 中的泛型的纯 DDD 实现。因此,我们有通用存储库、工作实现单元(基于代码的事务)和逻辑分离。我们可以轻而易举地模拟出数据集,并在数据库实现之前进行实际开发。构建这样一个框架需要预付费用,但是 商业逻辑再次成为这部剧的主角非常好。我们现在将数据作为资源使用,并用代码中本地使用的语言处理它。这种方法的另一个好处是它提供了明确的分离。例如,我不再在网页中看到数据库查询。是的,那页需要数据。是的,涉及到数据库。但是现在,无论我从哪里提取数据,都有一个(也只有一个)地方可以进入代码并找到它。也许对于小型项目来说没什么大不了的,但是当你在一个站点上有几百个页面或者在一个桌面应用程序中有几十个窗口的时候,你真的可以欣赏它。

作为一名开发人员,我被雇佣来使用我的逻辑和分析技能来实现业务需求——我们的框架实现使我现在更有生产力。作为一名经理,我宁愿让我的开发人员使用他们的逻辑和分析技能来解决问题,而不是编写 SQL。事实上,我们可以构建一个使用数据库的整个应用程序,直到开发周期接近尾声时才拥有数据库,这是一件美妙的事情。它并不意味着对数据库专业人员的抨击。有时数据库实现比解决方案更复杂。SQL (在我们的例子中,特别是视图和存储过程)是一个抽象点,代码可以将数据作为服务使用。在数据和开发团队之间存在明确分离的情况下,这有助于消除等待数据库实现和更改的等待模式。开发人员可以专注于问题领域,而不必停留在 DBA 上,而 DBA 可以专注于正确的实现,而不需要 就现在

SQL 有许多缺陷,正如这里的一些其他海报所指出的。尽管如此,我还是更喜欢使用 SQL,而不是人们提供的许多替代工具,因为“简化”往往比它们应该简化的东西更复杂。

我的理论是 SQL 是由一群象牙塔里的蓝色滑雪者发明的。整个非程序性结构。听起来不错: 告诉我你想要什么,而不是你想怎么做。但在实践中,仅仅给出步骤往往更容易。通常这看起来像是试图通过描述汽车完成后的性能来给汽车维护指导。是的,你可以说,“我希望汽车再一次达到每加仑30英里,并且在这样的嗡嗡声中行驶... ... 嗯... ... 等等”,但是对于每个人来说,说,“更换火花塞”不是更容易吗?即使您知道如何用非过程性的术语表达复杂的查询,数据库引擎通常也会提出一个非常低效的执行计划。我认为通过添加标准化的方法来告诉 SQL 首先读取哪个表以及使用哪个索引,SQL 将得到很大的改进。

对空值的处理让我抓狂!是的,从理论上来说,当有人说“嘿,如果 null 表示未知,那么将未知值加到已知值中应该会得到未知值”时,这听起来一定很棒。毕竟,根据定义,我们不知道未知价值是什么。”理论上,绝对正确。实际上,如果我们有1万名客户,我们确切地知道9,999人欠我们多少钱,但对于上一个客户欠我们多少钱,存在一些问题,管理层会说,“我们的总应收帐款是多少?”是的,数学上正确的答案是“我不知道”。但实际的答案是: “我们计算出了4,327,287.42美元,但有一个账户存在问题,因此这个数字并不准确。”。我敢肯定,管理层宁愿接近(如果不是确定数字的话) ,也不愿一脸茫然。但是 SQL 坚持使用这种数学上的原始方法,所以每次执行操作时,都必须添加额外的代码来检查 null 并对其进行特殊处理。

尽管如此,我还是宁愿使用 SQL,而不是使用构建在 SQL 之上的某个层,那只会创建另一套我需要学习的东西,然后我必须知道这最终会被转换成 SQL,有时我可以相信它会正确而有效地进行转换,但是当事情变得复杂时,我不能,所以现在我必须知道额外的层,我仍然必须知道 SQL,我必须知道它将如何转换成我可以欺骗这个层,让 SQL 做正确的事情。啊。

快,写我的 SQL 分页数据集工作在 MySQL,Oracle,MSSQL,PostgreSQL 和 DB2。

Oh, right, standard SQL doesn't define any operators to limit the number of results coming back and which row to start at.

SQL 非常适合某些类型的任务,特别是操作和检索数据的 设置

然而,SQL 缺少(或只是部分实现了)几个管理变更和复杂性的重要工具:

  • Encapsulation: SQL's encapsulation mechanisms are coarse. When you write SQL code, you have to know everything about the implementation of your data. This limits the amount of 抽象 you can achieve.

  • 多态性 : 如果希望在不同的表上执行相同的操作,则必须编写两次代码。(人们可以通过富有想象力地运用观点来缓解这种情况。)

  • 可见性控制 : 没有标准的 SQL 机制来隐藏代码片段或将它们分组成逻辑单元,因此每个表、过程等都是 可以从其他任何网站访问,即使是不受欢迎的网站

  • 模块化 和 < strong > 版本控制

最后,在 SQL 中手动编写 CRUD 操作代码(并编写代码将其连接到应用程序的其余部分)是重复且容易出错的。

现代抽象层提供了所有这些特性,并允许我们在最有效的地方使用 SQL,同时隐藏具有干扰性的、重复的实现细节。它提供了一些工具来帮助克服在面向对象软件开发中使数据访问复杂化的 对象关系不匹配

For experienced SQL programmer the bad sides are

  • 冗长
  • 正如许多人在这里所说的,SQL 是声明性的,也就是 优化不是直接的
  • Frameworks that try to address all possible dialects and don't support shortcuts of any of them
  • No easy version control.

对其他人来说,原因是

  • 有些程序员不擅长 SQL。可能是因为 SQL 使用集合,而编程语言使用对象或函数范式。集合思维(联合、产品、交叉)是一种有些人没有的习惯。
  • 有些操作并不是不言自明的: 比如,一开始并不清楚 哪里拥有是否过滤了不同的集合。
  • 方言太多了

The primary goal of SQL frameworks is to reduce your typing. They somehow do, but too often only for very simple queries. If you try doing something complex, you have to use strings and type a lot. Frameworks that try to handle everything possible, like SQL Alchemy, become too huge, like another programming language.

[26.06.10更新]最近我在 Django ORM 模块工作。这是我见过的唯一有价值的 SQL 框架。而这一个让工作的东西很多。不过,复杂的聚合有点困难。

SQL 是基于集合论的,而现在大多数高级语言都是面向对象的。对象程序员通常喜欢在对象中思考,因此不得不转变思维方式,使用基于 Set 的工具来存储对象。一般来说,(对于面向对象程序员来说)更自然的做法是在他们选择的语言中删除代码,然后在应用程序代码中执行 object.save 或 object.delete 之类的操作,而不必编写 sql 查询并调用数据库来实现相同的结果。

当然,有时候对于复杂的事情,SQL 更容易使用,也更有效率,因此对这两种类型的技术都有一定的了解是很好的。

最近我听说了很多关于 SQL 是一种糟糕的语言的事情,而且似乎每个框架都预先打包了一个资料库抽象层。

注意,这些图层只是将它们自己的内容转换成 SQL。对于大多数数据库供应商来说,SQL是与引擎通信的唯一方式。

但根据我的经验,SQL 通常是管理数据输入和输出的更简单、更通用和更程序员友好的方法。我使用的每一种抽象层似乎都是一种明显有限的方法,没有任何实际效果。

我上面描述的原因。

数据库层没有 任何东西,他们只是 限制你。它们使查询更简单,但从未更有效。

根据定义,数据库层中没有不在 SQL中的内容。

是什么让 SQL如此糟糕,为什么数据库抽象层如此有价值?

SQL是一种很好的语言,但是,它需要一些大脑的旋转来使用它。

In theory, SQL is declarative, that is you declare what you want to get and the engine provides it in the fastest way possible.

在实践中,有许多方法可以形成正确的查询(即返回正确结果的查询)。

The optimizers are able to build a Lego castle out of some predefined algorithms (yes, they are multiple), but they just cannot make new algorithms. It still takes an SQL developer to assist them.

但是,有些人希望优化器生成“可能的最佳计划”,而不是“在给定 SQL引擎实现的情况下,对该查询可用的最佳计划”。

我们都知道,当计算机程序没有达到人们的期望时,受到指责的是程序,而不是期望。

然而,在大多数情况下,重新设计查询可以产生尽可能好的计划。有些任务是不可能完成的,然而,随着 SQL的新的和不断增长的改进,这些案例的数量变得越来越少。

不过,如果供应商能提供一些底层访问函数,比如“ get the index range”、“ get a row by the rowid”等,比如 C编译器可以让你直接将汇编嵌入到语言中,那就再好不过了。

我最近在我的博客上写了一篇关于这个的文章:

最近经常听到吗?我希望你不要把这个和 NoSql 运动搞混了。据我所知,这主要是一群人谁使用 NoSql 的高可伸缩性网络应用程序,似乎忘记了 SQL 是一个有效的工具在非“高可伸缩性网络应用程序”的情况下。

抽象层的业务就是找出面向对象代码和基于表集的代码(如 SQL 喜欢说话)之间的区别。通常这会导致编写大量的锅炉板和沉闷的两者之间的过渡代码。ORM 自动化了这一点,从而为业务对象人员节省了时间。

我认为框架中包含一个资料库抽象层是件好事,因为它解决了两个非常重要的问题:

  1. 这样代码就清晰了。通过将 SQL 放到另一个层中,这个层通常非常薄,应该只做基本的查询和结果切换(以一种标准化的方式) ,您可以让您的应用程序免受 SQL 的干扰。这和 web 开发人员(应该)把 CSS 和 Javascript 放在不同的文件中的原因是一样的。如果你能避免它,do not mix your languages

  2. 许多程序员在使用 SQL 方面一窍不通。无论出于什么原因,大量的开发人员(尤其是 web 开发人员)似乎非常非常不善于使用 SQL 或 RDBMS。他们将数据库(以及扩展后的 SQL)视为获取数据所必须经过的肮脏的小中间人。这将导致考虑极差的数据库,没有索引,表以可疑的方式堆叠在表的顶部,以及编写非常糟糕的查询。或者更糟糕的是,他们试图过于笼统(专家系统,有人吗?)无法以任何有意义的方式合理地关联数据。

不幸的是,有时候,人们试图解决问题的方式和他们使用的工具,不管是由于无知、固执或其他特点,都是直接相互对立的,希望你能说服他们相信这一点。因此,除了作为一个好的实践,我认为资料库抽象层是一种安全网,因为它不仅使 SQL 远离可怜的开发人员的眼睛,而且使他们的代码更容易重构,因为所有的查询都在一个地方。

没有人喜欢 SQL,因为 SQL 在语法、语义和当前用法上都很糟糕:

  • 它的语法是一个 cobol 弹片,所有的 cobol 批评都适用于这里(公平地说,程度较轻)。尝试成为自然语言,而不尝试解释自然语言会产生任意的语法(是 DROP TABLE 还是 DROP,UPDATE TABLE,UPDATE 还是 UPDATE IN,DELETE 还是 DELETE FROM...) ,以及像 SELECT (它能填满多少页?)这样的语法怪物
  • semantics is also deeply flawed, Date explains it in great detail, but it will suffice to note that a three valued boolean logic doesn't really fit a relational algebra where a row can only be or not be part of a table
  • 将一种编程语言作为数据库的主要(通常也是唯一)接口被证明是一个非常糟糕的选择,它创造了一种新的安全缺陷类别

每个厂商都扩展了 SQL 语法来满足自己的需求。因此,除非您正在做相当简单的事情,否则您的 SQL 代码是不可移植的。

• The syntax of SQL is not orthogonal; e.g., the select, insert, update,anddelete statements all have completely different syntactical structure.

我认为人们使用 SQL 的问题与关系设计和 SQL 语言本身没有任何关系。它与数据层建模有关,数据层建模在许多方面与业务层或接口建模有着根本的不同。表示层建模中的错误通常比数据层更容易纠正,在数据层中有多个应用程序使用数据库。这些问题与在 SOA 设计中对服务层进行建模时遇到的问题相同,您必须考虑到服务的当前使用者以及输入和输出契约。

SQL 被设计用来与关系数据库模型交互。还有一些其他的数据模型已经存在了一段时间,但是无论使用什么样的理论模型,正确设计数据层的原则都是存在的。因此,开发者在使用 SQL 时遇到的困难通常与试图将一个非关系数据模型强加到一个关系数据库产品上有关。

这里的许多文章似乎认为 SQL 是不好的,因为它没有“代码优化”特性,并且您无法控制执行计划。

SQL 引擎所擅长的是为书面指令提出一个执行计划,面向 资料,即实际的 内容。如果您不想局限于编程方面,您将看到在应用程序层之间传递的不仅仅是字节,还有更多的数据。

虽然 SQL 确实完成了工作,但它肯定存在问题... ..。


  • 它试图同时是高级和低级抽象 ,这就是 ...单数。也许它应该是两个或两个以上不同层次的标准。
  • 作为一个标准,这是一个巨大的失败。当一个标准要么搅乱一切,要么对实现要求太多,要么要求太少,或者出于某种原因没有实现部分社会目标,即激励供应商和实现者生产出严格一致的可互操作的完整实现时,很多事情都会出错。当然,您不能说 SQL 已经完成了上述任何操作。看看其他一些标准,并注意标准的成败显然是取得有益合作的一个因素:
    • RS-232(很糟糕,几乎没有足够的指定,甚至哪个引脚传输和哪个引脚接收是可选的,shesh。你可以服从,但仍然一事无成。成功互操作的机会: 非常低,直到 IBM 个人电脑制定了一个事实上有用的标准。)
    • IEEE 754-1985浮点数(很糟糕,超越: 没有一台超级计算机或科学工作站或 RISC 微处理器曾经采用过它,尽管最终在20年后我们能够很好地在 HW 中实现它。至少这个世界最终成长了。)
    • C89、 C99、 PCI、 USB、 Java (很好,无论是标准还是规范,他们成功地激励了几乎所有人的严格遵从,而这种遵从导致了成功的互操作。)
  • 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.