RavenDB回顾:无界结果集


我们最近花了一些时间研究了很多旧的设计决策。其中一些在今天几乎没有意义(JSON vs.blittalbe就是一个很好的例子),但在当时非常有意义,而且对于真正推出产品是必不可少的。

然而,其中一些设计决策仍然是我非常坚信的。本系列文章将探讨这些决定,它们的背景以及它们在现实世界中是如何发挥作用的。所以,废话不多说,让我们谈谈无界结果集。

RavenDB的设计很大程度上受到了我在NHibernate方面的经验的影响(如果你相信的话,我在十多年前就开始使用NHibernate了),在那里我看到了相同类型的错误,一次又一次地重复。然后我读到Release It!我突然发现我并不是一个人在对抗那些恶魔。当我设计RavenDB时,我就明确地着手尽可能多地防止这些问题。

我想说的一个主要问题是Unbounded Result Sets,简单地说,这就是当你有:

SELECT * FROM OrderLines WHERE OrderID = 1555

而且您没有意识到这个订单有300万个行项目(或者,更糟糕的是,您的大多数订单只有几千个行项目,因此您在数据库上产生了大量的负载,结果却扔掉了大部分)。

为了防止这种类型的问题,RavenDB有强制页面大小的概念。

  • 在客户端,如果您没有指定限制,我们将隐式地添加一个(默认情况下为128)。
  • 在服务器端,有一个数据库范围的最大页面大小(默认设置为1024)。如果页面大小较大,服务器将将其修剪到最大值。

我认为这是RavenDB设计中一个比较有争议的决定,也是一个得到了很多热烈讨论的决定。但我仍然认为这是个好主意,因为我看到了当你不要那样做。

争论主要是关于“RavendB应该相信开发人员知道他们在做什么”,当我外出购物时,一个特别愤怒的家伙打电话给我,抱怨我违反了Linq的神圣契约,即“查询应该默认返回所有结果,即使这是100亿个结果”。我指出,这实际上是可配置的,如果他想将默认值设置为任何他想要的大小,他可以这样做,但显然这应该是“先射我自己的脚,然后再思考”的交易。

即使这样,我仍然认为这是一个真正的好主意,多年来,我们添加了一些特性,使人们在需要时能够轻松地访问整个数据集。从2.5左右开始,流就已经出现了,它提供了一个专用的API来流化无界的结果。构建流是为了使处理大型数据集的效率更高,它们允许客户机和服务器并行处理数据,而不是在服务器上批量处理巨大的响应,然后在给出完整的结果集之前在客户机上消耗大量的内存。相反,您可以在每个结果从服务器到达时立即获得它,然后处理它并将其进一步发送。

在4.0中,我们将更改分页限制的行为,如下所示:

  • 如果你方不指定限额,我们将提供25项的限额条款。如果条目超过25个,我们将抛出一个异常(除非您在约定中另有要求)。
  • 如果您显式地提供一个限制,它将按预期工作并在数据中进行分页。

我们的想法是,我们想要减少给用户带来的惊喜,这可以给他们早期的体验。我们要做的另一件事是确保操作人员也能改变它,很可能使用环境变量或类似的东西。如果您需要动态地修改约定,则通常很难部署新版本,因此需要立即采取行动。

通过这种方式,我们可以帮助用户避免向服务器发出昂贵的请求,并且他们可以明确说明他们需要做什么。