重新思考数据库 | 嵌套查询和链式查询,有什么区别吗?

lit*_*ito 6 rethinkdb rethinkdb-javascript

链式有什么区别:

r.db('catbox').table("bw_mobile").filter(
    r.row("value")("appVersion")("major").le(2)
).filter(
  r.row("value")("appVersion")("minor").le(2)
).filter(
  r.row("value")("appVersion")("patch").le(10)
)
Run Code Online (Sandbox Code Playgroud)

嵌套:

r.db('catbox').table("bw_mobile").filter(
      r.row("value")("appVersion")("major").le(2).and(
        r.row("value")("appVersion")("minor").le(2).and(
          r.row("value")("appVersion")("patch").le(10)
        )
      )
)
Run Code Online (Sandbox Code Playgroud)

或 lambda 函数

r.db('catbox').table("bw_mobile").filter(
  r.js("(function (session) { 
        return session.value.appVersion.major < 0 
            || ( session.value.appVersion.major == 0 && session.value.appVersion.minor < 0 )
            || ( session.value.appVersion.major == 0 && session.value.appVersion.minor == 0 && session.value.appVersion.patch < 71 )
        ; 
    })")
)
Run Code Online (Sandbox Code Playgroud)

泰!

Lyu*_*riv 3

我认为第二种情况(单个filter有多个and表达式)是最高效、最方便使用的。我会考虑以下想法:

r.filter正如记录的那样,无论传递给 的谓词函数的结果如何,总是r.filter创建一个新的选择、一个流或一个数组。我不确定 RethinkDB 中如何实现选择(我相信它们是类似流的),但数组链接可能是分配中间数组的昂贵操作。将此与Array.prototype.filter创建一个新数组作为结果进行比较。流是惰性的,因此每个元素也被延迟计算(或不延迟计算),从而产生更小的内存占用。将此与其他语言中的迭代器/流和生成器(Java 中的Iterator<E>/和.NET/C# 中的 /,JavaScript 中的迭代器和生成器函数,Python 中的迭代器和生成器函数,shell 命令中的管道等)进行比较,您可以在其中组合迭代器/生成器。无论如何,你都有中间过滤器。Stream<E>IEnumerator<T>yield returnyield|

单个表达式可以代替一堆链式过滤器操作。请注意,r.and表达式中的操作有一个非常重要的特征:这是一种短路求值操作。如果 AND 运算的左侧操作数是false,则该运算甚至不需要计算右侧表达式即可获得始终为falsethen 的结果。你不能用 做这样的事情r.filter。将此与每个单个查询可以指定一次的 SQL WHERE 子句进行比较(所有错误情况都可以由AND运算符简单地丢弃)。此外,从实用的角度来看,您可以创建一个工厂方法,该方法可以具有方便的名称并返回参数化的 ReQL 表达式,甚至可以将其分配给常量,因为 ReQL 表达式是不可变的并且可以安全地重用:

const maxVersionIs = (major, minor, patch) => r.row("value")("appVersion")("major").le(major)
    .and(r.row("value")("appVersion")("minor").le(minor))
    .and(r.row("value")("appVersion")("patch").le(patch));

const versionPriorToMilestone = maxVersionIs(2, 2, 10);

...

.filter(maxVersionIs(major, minor, patch))

...

.filter(versionPriorToMilestone)
Run Code Online (Sandbox Code Playgroud)

ReQL 表达式 RethinkDB 查询实际上是表达式树,比执行 JavaScript 脚本更容易解析并直接转换为执行计划。官方文档甚至建议避免使用r.js以获得更好的性能。我猜这里的成本是 JavaScript 运行时设置、独立的脚本执行和检查脚本超时。此外,脚本更容易出错,而表达式树可以在编译期间或多或少地进行检查。但是,为了完整起见,r.js即使有这些成本,也可以更强大,因为 ReQL 是一组有限的操作。从我个人的经验来看:我必须实现一种基于 RethinkDB 的权限检查子系统,并且我需要在 RethinkDB 中进行按位 AND 运算。不幸的是,RethinkDB 从 2.3 开始不支持按位运算,所以我不得不使用r.js: r.js('(function (user) { return !!(user.permissions & ${permissions}); })')。RethinkDB 的未来版本将支持按位运算,因此r.getField('permissions').bitAnd(permissions))将来的某一天应该会更快地工作,并且可以与其他表达式组合以适应单个filter.