优化的批量(块)上传对象到IndexedDB

时间:2014-03-07 10:31:37

标签: javascript indexeddb

我想在一个事务中将对象添加到IndexedDB中的某个表中:

_that.bulkSet = function(data, key) {
    var transaction = _db.transaction([_tblName], "readwrite"),
        store = transaction.objectStore(_tblName),
        ii = 0;

    _bulkKWVals.push(data);
    _bulkKWKeys.push(key);

    if (_bulkKWVals.length == 3000) {
        insertNext();
    }

    function insertNext() {
        if (ii < _bulkKWVals.length) {
            store.add(_bulkKWVals[ii], _bulkKWKeys[ii]).onsuccess = insertNext;
            ++ii;
        } else {
            console.log(_bulkKWVals.length);
        }
    }
};

看起来它工作正常,但它不是非常优化的方式,特别是如果对象的数量非常高(~50.000-500.000)。我怎么可能优化它?理想情况下,我想先添加3000,然后从数组中删除它,然后添加另一个3000,即以块为单位。有什么想法吗?

2 个答案:

答案 0 :(得分:16)

连续插入那么多行,不可能获得良好的性能。

我是一个IndexedDB dev,并且在您正在谈论的规模(连续写入数十万行)中拥有IndexedDB的实际经验。它不太漂亮。

在我看来,当必须连续写入大量数据时,IDB不适合使用。如果我要构建一个需要大量数据的IndexedDB应用程序,我会想出一种随着时间的推移慢慢播种的方法。

问题在于写入,我认为问题在于写入的缓慢以及它们的i / o密集性使得随着时间的推移会变得更糟。 (读取总是在IDB中快速减轻,因为它的价值。)

首先,您可以通过重新使用交易获得节省。因此,你的第一直觉可能是尝试将所有东西塞进同一个交易中。但是,例如,我在Chrome中发现的是,浏览器似乎不喜欢长时间运行的写入,可能是因为某些机制意味着限制行为不当的标签。

我不确定你看到的是什么样的表现,但平均数字可能会欺骗你,具体取决于你的测试大小。限制更快的是吞吐量,但如果你试图连续插入大量数据,请特别注意随时间的写入。

我正好正在制作一个拥有数十万行的演示,并拥有统计数据。在禁用我的可视化功能的情况下,在IDB上运行纯粹破折号,这就是我在Chrome 32中在单个对象存储上看到的内容,其中包含一个带有自动递增主键的非唯一索引。

一个更小,更小的27k行数据集,我看到60-70个条目/秒:
* ~30秒:平均921个条目/秒(开始时总是有大量插入),在我采样的那一刻是62 /秒 * ~60秒:389 /秒平均值(持续降低开始超过初始爆发效果)71 /秒时刻
* ~1:30:258 /秒,当时为67 /秒 * ~2:00(约1/3完成):平均188 /秒,时刻66 /秒

具有小得多的数据集的一些示例显示出更好的性能,但具有相似的特征。同样大得多的数据集 - 效果被夸大了,我在离开多个小时时看到的每秒只有1个条目。

答案 1 :(得分:1)

IndexedDB实际上是为优化批量操作而设计的。问题是该规范和某些文档并没有使它起作用。如果特别注意IndexedDB specification中定义IDBObjectStore中所有变异操作如何工作的部分(add(),put(),delete()),您会发现它允许调用者调用它们同步并忽略监听成功事件,但忽略最后一个。通过省略该操作(但仍然听错),您将获得巨大的性能提升。

This example using Dexie.js shows the possible bulk speed,因为它会在680 ms的Macbook Pro上(使用Opera / Chromium)在680毫秒内插入10,000行。

Dexie.js库中的Table.bulkPut()方法完成:

db.objects.bulkPut(arrayOfObjects)