使用图形数据库构建您的下一个应用程序

2020-07-10 03:58:54

“为什么我的应用程序应该使用图形数据库,而不是关系数据库?

人们倾向于从关系数据库开始他们的技术之旅,并被困在那里。因此,对他们来说,存在一个问题,那就是为什么要背离他们知道的“正确”。对我来说,最快的反应看起来是这样的:

但这不是理由。这是我基于我所拥有的经验和我所使用的技术而做出的反应。

在这篇文章中,我将解释为什么你的下一款应用程序应该信任图形数据库,而不应该信任关系数据库。

很多时候,这样的讨论是从以下角度提出的:为什么要离开关系平台;为什么要做默认选择之外的事情?我打算扭转这一局面,相反,我认为,对于大多数应用程序来说,图形数据库应该是默认选择,而你需要一个很好的理由才能走上另一条路。

我将首先指出,关系数据库可能是您的默认选择,因为历史上的偶然性、教育偏见和一些群体思维,而不是因为它们适合您的工程需求。许多人对一种不同的技术的最初反应的一部分,只是归结为熟悉:你已经超越了最初学到的很多东西;不要拘泥于这一点。

在这一点上,我将从工程学的角度得出关系型数据库不好用的原因,从而将这篇文章的论点转变为图形数据库易于使用,自然适合你的应用程序,通过使用图形数据库,你就不必花时间在技术堆栈底部的怪物周围进行工程设计了。在这方面,我将从工程学的角度得出结论,即图形数据库易于使用,自然适合你的应用程序,通过使用图形数据库,你不必花费时间在技术堆栈底部的怪物周围进行工程设计。

从那时起,我们将开始数据建模,然后是查询执行,最后是速度和规模。在阅读这些部分时,您会注意到我已经占据了我的位置:图形数据库是您的应用程序的自然选择;以下是原因。

我认为从工程简易性、技术适用性和图形数据库如何处理请求的机制的角度来看,我是这样认为的。这不是一篇关于图形数据库的一些好观点的文章。这是自然而然的做法,给我一个不这样做的理由。

你可能会下意识地感觉到,你想为你的应用程序选择关系数据库辩护,为什么所有从你的应用程序的图形转换成一些表和连接的中间技术都是有意义的;这很好,但你需要一个很好的论点才能通过这一点。

大多数工程师学到的第一件事就是关系数据库。在技术堆栈的底部想一件不同的事情是一种心理障碍。但是你学到了你现在不用的语言,学到了已经过时的技术,学到了你的组织没有遵循的做法。这也没什么不同。

您学到的关系数据库完全是个意外。这很简单,因为它们是一种被广泛使用的早期技术,所以你的老师知道它们,更重要的是,它们是教学的梦想。

关系数据库以关系代数为基础。这意味着关系数据库课程是一个漂亮的包:从理论基础开始,混合一些实际应用程序,深入到工程挑战中。它是计算机科学,教起来很棒,而且很容易评估。

但是,当关系数据库是您的技术堆栈中的最底层时,它们就不是那么干净和奇妙了。

在应用程序中使用关系数据库既不是教人的梦想,也不容易评估。设计选择和绕过关系数据库作为接口呈现给您的内容通常是一件苦差事。

你看,在你学习构建软件的那套课程中,你学了一门关于软件设计和好的软件设计原则的课程。在此过程中,您了解了是什么使软件组件设计良好,并且易于从其他组件中使用。您学到了所有关于抽象、接口和依赖项的知识,然后,您走出了那门课,进入了数据库101。您的数据库课程中介绍的组件基本上是所有好的软件工程设计原则的反例。

关系数据库在很大程度上是好的软件设计的反例,以至于开发历史上充斥着让它们变得更好的想法。任何开发过大型应用程序的人都知道,以某种方式处理堆栈底部的那些难以驾驭的技术是您面临的关键工程挑战之一。

你把它包装在ORM中,编写一些定制的东西,抓住你可以使用的所有工具来驯服这样一个事实,即你的应用程序的基石以一种从软件工程的角度来看一点也不好的方式暴露出来。您被迫以它的方式建模,然后,它将其内部工作作为一个接口强加给您。

您必须隐藏关系数据库。如果你不这样做,你的应用程序的代码和它强加给你的模型和界面之间就会有太多的依赖。

然而,不知何故,它到处都在漏水。你经常面临着围绕它的工程挑战。您必须弄清楚DB中的更改如何渗透到您的包装器中,这对连接性能意味着什么,如何才能强制包装器在不向应用程序添加将您绑定到数据库内部工作的魔力字符串的情况下获得您需要的一些数据。

事实上,我们如此着迷于围绕关系数据库进行工程的挑战,并且在处理这些挑战时变得如此熟练和熟练,以至于我们忘了问是否有更简单的方法。

这种情况如此根深蒂固,以至于它在某种程度上已经成为软件工程的一个文化方面。愿意承担和解决关系数据库的工程挑战几乎被视为一种荣誉勋章,深入了解它们是如何工作的,如何用它们施展黑魔法被视为知识和智慧的标志,质疑额外的努力在某种程度上是软件工程的诅咒。

即使在GraphQL生态系统中,整个公司的生存也是基于这样的前提:他们可以驯服这只工程怪兽,如果你通过添加他们的层来深化你的技术堆栈,你将能够更好地应对翻译和工程挑战,从而达到你想要的--也就是以一种对你的应用来说很自然的方式进行建模,并拥有一个数据接口,而不会给你带来问题。为什么要从关系开始呢?为什么一开始就假设核心技术是固定的,我们必须找到更具创造性的工程方法来绕过它的缺陷呢?

当你处理一个关系数据库时,你得到的是一项高度工程化的技术,而不是一项很容易设计的技术。它破坏了您所知道的每一个软件工程原则,并迫使您做比仅仅为了驯服它而需要做的更多的工作。

有了图形数据库,许多挑战就迎刃而解了。你的数据模型是你的应用程序的更自然的抽象,查询在你的应用程序的数据模型中更自然地遍历,特别是如果你的项目是Dgraph上的GraphQL项目,你用来访问数据的界面就会与你一起工作-这不是你必须围绕着设计的东西。

信任你的应用程序的图形数据库:你会得到一项与你一起工作的技术,而不是强迫你绕过它进行工程设计的一项技术。

正因为如此,这篇文章的视角发生了变化。不要认为关系数据库是你的应用程序的自然选择;它是不自然的选择;它是迫使你做更多工作的选择;它是迫使你做智力体操的选择,无论是为了建模还是查询;它是迫使你做你不需要做的、与你的应用程序无关的工程工作的选择。(注:关系数据库是你的应用程序的自然选择;它是非自然的选择,它迫使你做更多的工作;它是迫使你做建模和查询的心智体操的选择;它是强迫你做你不需要做的、与你的应用程序无关的工程工作的选择。

图形数据库提供了一个简单的建模抽象,它自然地符合您在心理上如何看待您的应用程序,以及您的编程语言中的数据结构将如何使用该应用程序的数据。使用GraphQL,您还可以获得端到端类型,这意味着您的应用程序和您的模型具有相同的数据视图。

让我们举一个简单的例子,一个带有可能有评论列表的卡片的Trello克隆。在我的Dgraph GraphQL世界里,这只是卡片和评论之间的一个边缘。

让我们忽略共享抽象的任何概念-例如,卡片和注释都是列出创建者、日期等的某个接口的扩展-在关系世界中变得更加困难,在图形世界中变得更容易,并且只采用最简单的可能模型。我该怎么做才能以关系的方式对此进行建模呢?嗯,这个最简单的例子是相似的,但是已经不符合我的思维模式了。

关系建模将有两个表,同样是CARD和COMMENTS,并且将列出相同的属性,除了我被迫在COMMENT表中而不是在CARD表中放入对卡的引用。而且,即使是在最简单的情况下,我也必须打破我对这些数据的思维模式。我永远不会以这种方式遍历数据;我将始终布局卡片的页面或弹出窗口、其详细信息和评论列表。但是关系数据库把它的内部工作强加给了我。我还必须认识到,在查询时,我不能遵循我的思维模型;我必须将其转换为连接。我想去card.评论,而不是找到card,然后在comment.card=card.id的地方找到评论,但我不能。

我的建模不是由我如何在头脑中查看数据或我的应用程序如何使用数据来管理的,而是由关系数据库的内部工作方式决定的。即使在最简单的情况下,我的工程设计也将基于数据库的内部工作,而不是我的应用程序。

如果模型更复杂,那么它在图形世界中也一样好,但在关系世界中就不一样了。例如,一张卡可以有多个受理人。在我的Dgraph GraphQL模型中,我简单地说明了卡片链接到人的自然模型。

然而,我的关系模型变得很奇怪。我不能代表这个。我不仅要创建Person和Card表,现在还要创建表示此链接的第三个表cardAssignment。我的问题也同样改变了。我不能出牌。任务接受者,我现在必须连接三个数据块并做两个预测。

随着我构建更多的应用程序,这种差异越来越大。在图表方面,我对我的数据和我的应用程序关心的关系进行建模。在关系方面,我关心的是数据库是如何工作的,我可以使用什么技巧将我的模型压缩到其中,我如何才能使其性能更好,我是否需要对数据库进行反规范化。

关系模型确实“管用”,但它的工作量更大,并且增加了不必要的复杂性和脑力操练。您甚至可以通过添加ORM来帮助您加深技术堆栈和依赖关系。但是为什么呢?我过去曾被这样的话挑战过,比如“我还没有发现一个案例是用无法在关系数据库中建模的图表来建模的”,这很可能是真的,但我也“没有见过挖掘机挖出的洞不是用铲子挖的”。当然,这两种说法都是正确的,但你会想让别人拿着铲子吗?

为什么要引入这种复杂性?我不会。这个模型是关于卡片、评论和受让人的图表。我想让它保持这种状态。我想用这种方式来考虑我的应用程序。我想这样问一下。我不想绕过其他的事情。

信任图形数据库来为您的应用程序建模:它与您一起对您的域进行建模,而不是强迫您根据其内部工作方式对其进行建模。

对不起,读者。我本打算在图形建模上花费更多的文本,而不是关系建模,但是关系花了如此多的时间来解释,以至于它最终在这里占据了文本的主导地位。图表版本很简单,卡片可以有一个受让人列表。但即使与关系版本相比,我也不得不告诉你它的内部工作原理--这些东西是如此有害,以至于你不能在不了解内部细节的情况下用它们建模,而且,看起来,如果没有它们的内部细节,你甚至无法谈论它们。

图形数据库中的查询执行与您获取应用程序数据的方式相匹配。

我已经有了我的模型-卡片、评论和受让人-我想要这些数据来布局页面。您可能不熟悉GraphQL语法,但它只是对我需要的数据遍历的描述。

获取这张卡片,跟随评论边缘获取所有评论,跟随受让人边缘获取分配到这张卡片的人员。好了。

关系版本,嗯-不,我这次不会描述它。我不会仅仅为了解释这个简单的查询而描述数据库的内部工作。就像在上一节中一样,这会导致关系兔子洞。你知道这要复杂得多。你知道,这都是关于表连接、投影和叉积的。您知道关系查询返回一个数据块,但是在这里,我们不想要一个块,我们想要这个子图。我的街区里的这些排在这里会是什么样子呢?我是编写单个查询并让各行重复每个评论的卡片数据,还是运行多个查询、多次往返?

等等,我们为什么要考虑这一点:我们想要为我们的应用程序提供一些数据,而不是了解另一项技术的内部工作原理。您的应用程序还使用了多少其他库或组件,这迫使您必须深入了解它们的内部工作原理,才能开始使用它们。没有。它只是一个关系数据库。

信任图形数据库来查询您的数据:您的查询将是关于您的数据的,而不是关于数据库的内部工作的。

好的,解释Dgraph如何存储数据的最简单方法是,边就像编程语言中的指针一样存储。因此,当查询从卡片遍历到评论列表时,这很像(基于光盘的)指针查找。最终结果是,对于dgraph来说,要找到数据来布局我们的卡片、它的注释和受让人,dgraph只需要使用涉及的实际数据。查找卡片,沿着卡片的边缘找到注释和受让人。如果涉及到更多的边,就顺着这些边走。

您如何编写查询和数据库如何执行查询的图表版本都是关于应用程序的数据以及它是如何链接的。关系版本是关于数据块、这些块的子集和多个连接的,我的连接是一个问题吗,我是否必须多次旅行才能产生N+1问题。

相信图形数据库可以在你的应用程序中执行查询:它的工作原理是使用你的图形来找到你需要的数据,而不是固定在某种代数理论上,这些理论在教科书上看起来像是一个不错的练习。

如上所述,对于图形数据库,查询执行方法是处理图形。事实证明,这是快速的,而且,在Dgraph的情况下,是可伸缩的。Dgraph的数据存储格式和处理查询的方式都进行了优化,以解决GraphQL查询要求的各种问题。

有两个问题往往会影响GraphQL查询的性能。一个是扇形,另一个是深度。当查询请求更多字段时,有更多的工作要做,每个级别要返回的数据也更多。随着情况的加深,这可能会增加到磁盘获取数据的次数和N+1个问题。

查询扇出在Dgraph中不是问题,因为它可以独立和并行地解决每个查询字段的问题。这意味着要求更多的字段并不一定要花费更多的时间。

Dgraph中的深度只意味着遵循另一个级别的指针。一些解决深度问题的方法,比如编译一个较大的查询,需要额外的表连接,另一些方法则从一个节点移动到它的N个兄弟节点,并产生N+1个查询问题。Dgraph并行推进查询边界,并且总是进行批处理,避免多次获取相同的节点,因此更深层次的遍历不是问题。

例如,如果查询从卡片扩展到评论、评论作者、分配给他们的其他卡片等等,则在GraphQL中可能如下所示。

getCard(id:";0x123";){.。评论{.。文本作者{username assignedCard{assignees{.}。

可能有N个注释,但<;N个不同的作者,因为同一作者可能会有多个注释,所以Dgraph会将注释展开,然后将作者作为一批展开(有效地作为指针取消引用),对于分配的卡片也是如此-批处理并最小化以避免重复工作。Dgraph就是为您解决这些GraphQL查询问题而设计的。

在关系数据库中实现这样的应用程序给您带来了工程挑战。您是否要在查询中过度获取或不足获取数据,是否要将查询编译为效率可能较低的单个连接,因为它将包含自连接,您是否需要设计一些程序来处理批处理和N+1。

在Dgraph中,查询成本受查询调查和返回的数据的限制,在关系实现中,它受工程工作的限制,以包含各种实现问题,并且通常还受连接的表的大小的限制。

Dgraph的查询机制也支持缩放。数据可以跨分布式群集进行复制和分片。查询应答机制不变。您不必编写不同的查询或设计分布式连接的解决方案,它可以在图形数据库中解决。对于SQL数据库,您从单个实例开始,设计查询,然后进行扩展。

信赖图形数据库的速度和规模:高效执行GraphQL的工程挑战,即使是大规模的,都由Dgraph解决,而不是作为另一个工程挑战强加给您。

最后,工程师应该做出与他们的技术需求相匹配的明智选择,所以我将把这个选择留给你。我只是希望我至少已经打开了一扇小小的心灵之门,让你意识到许多人认为的“默认”选择可能与你作为一名工程师想要做的事情不符。

你能不能简单地忽略所有的争论,只写你的应用程序。嗯,不是的,因为你做出的技术选择可能会帮助你构建你的应用程序,或者迫使你绕过它们,只是为了达到构建你的应用程序的目的。

当许多大公司无法再承受工程成本时,它们就会放弃关系数据库。然而,他们很早就遇到了工程问题,花了很多时间和精力来处理。谷歌(Google)、Facebook、Twitter、领英(LinkedIn)和其他公司一旦规模大到可以进行内部图形解决方案的工程设计工作,就都开始行动了,但这并不意味着你必须等那么长时间才能减轻工程方面的痛苦。

上图:这幅艺术家的构思展示了一名宇航员在火星上,通过航天器的窗户观看。美国宇航局正在将宇航员送回月球,并将在那里测试有助于将第一批宇航员送往这颗红色星球的技术。