向超过百万条记录的现有文档添加字段

Add field to existing documents over million records

场景

我们在一个存储桶中有超过 500 万份文档,所有文档都嵌套了 JSON 一个简单的 uuid 键。我们想为所有文档添加一个额外字段。

例子

ee6ae656-6e07-4aa2-951e-ea788e24856a
{
   "field1":"data1",
   "field2":{
      "nested_field1":"data2"
   }
}

添加额外字段后

ee6ae656-6e07-4aa2-951e-ea788e24856a
{
   "field1":"data1",
   "field3":"data3",
   "field2":{
      "nested_field1":"data2"
   }
}

它只有一个主索引:CREATE PRIMARY INDEX idx FOR bucket

问题

这需要很长时间。我们用 n1ql 试了一下,UPDATE bucket SET field3 = data3。还有子文件突变。但所有这一切都需要几个小时。它是用 Go 编写的,所以我们可以将它放入一个 goroutine 中,但是时间还是太长了。

问题

有什么解决办法可以减少那个时间吗?

由于您需要添加新字段,而不是修改任何现有字段,因此最好使用 SDK SUBDOC API vs N1QL UPDATE(这是整个文档更新并需要获取文档)。

最好的选择是使用 N1QL 获取文档密钥然后使用 SDK SUBDOC API 添加你需要的字段。您可以使用反应式 API(异步)

您有 500 万个文档,主索引使用如下

val = ""
In loop
    SELECT RAW META().id FROM mybucket WHERE META().id > $val  LIMIT 10000;
    SDK SUBDOC update
    val = last value from the SELECT

https://blog.couchbase.com/offset-keyset-pagination-n1ql-query-couchbase/

Eventing Service 可以非常高效地执行这些类型的丰富任务。即使是低端系统也应该能够在两 (2) 分钟内完成 500 万行。

// Note src_bkt is an alias to the source bucket for your handler
// in read+write mode supported for version 6.5.1+, this uses DCP 
// and can be 100X more performant than N1QL.

function OnUpdate(doc, meta) {
    // optional filter to be more selective
    // if (!doc.type && doc.type !== "mytype") return;

    // test if we already have the field we want to add
    if (doc.field3) return;

    doc.field3 = "data3";
    src_bkt[meta.id] = doc;
}

有关 Eventing 的更多详细信息,请参阅 https://docs.couchbase.com/server/current/eventing/eventing-overview.html 我通常会丰富 10 亿个文档中的 3/4。如果您将 Eventing 函数设置中的工作人员数量从 3 增加到 16,Eventing 函数也会 运行 更快(每秒丰富更多文档),前提是您的 Eventing 节点上有 8 个以上的物理核心。

我测试了上述 Eventing 函数,它在我的非 MDS 单节点 couchbase 测试系统(12 核,2.2GHz)上仅用了 72 秒就丰富了 5M 文档(以您的示例为模型)。显然,如果你有一个真正的多节点集群,它会更快(也许所有 5M 文档仅需 5 秒)。