我可以测量 TableBatchOperation 的大小吗?

Can I measure a TableBatchOperation's size?

TableBatchOperation 的 .Net SDK 文档说

A batch operation may contain up to 100 individual table operations, with the requirement that each operation entity must have same partition key. A batch with a retrieve operation cannot contain any other operations. Note that the total payload of a batch operation is limited to 4MB.

很容易确保我不会向批处理中添加超过 100 个单独的 table 操作:在最坏的情况下,我可以检查 Count 属性。但是除了手动序列化操作(此时我已经失去了使用 SDK 的大部分好处)之外,还有什么方法可以检查负载大小吗?

添加实体时,您可以跟踪名称和数据的大小。假设您使用的是默认为 Json 的较新库,添加的其他字符应该相对较小(与接近 4MB 的数据相比)且可估计。这不是一条完美的路线,但它会让你接近。

在进行过程中进行序列化,尤其是当您实际上经常接近 100 个实体限制或 4MB 限制时,除了会损失任何便利之外,还会使您失去很多性能。与其尝试通过估计大小或序列化进行跟踪,不如按原样发送批处理请求,如果收到 413 指示请求正文太大,请捕获错误,将批处理一分为二,然后继续。

我遵循 Emily Gerner 的建议使用乐观插入和错误处理,但使用 StorageException.RequestInformation.EgressBytes 来估计符合限制的操作数。除非操作的规模变化很大,否则这应该更有效。有理由不每次都提高 len,但这里有一个每次都回到乐观的实现。

        int off = 0;
        while (off < ops.Count)
        {
            // Batch size.
            int len = Math.Min(100, ops.Count - off);
            while (true)
            {
                var batch = new TableBatchOperation();
                for (int i = 0; i < len; i++) batch.Add(ops[off + i]);

                try
                {
                    _Tbl.ExecuteBatch(batch);
                    break;
                }
                catch (Microsoft.WindowsAzure.Storage.StorageException se)
                {
                    var we = se.InnerException as WebException;
                    var resp = we != null ? (we.Response as HttpWebResponse) : null;
                    if (resp != null && resp.StatusCode == HttpStatusCode.RequestEntityTooLarge)
                    {
                        // Assume roughly equal sizes, and base updated length on the size of the previous request.
                        // We assume that no individual operation is too big!
                        len = len * 4000000 / (int)se.RequestInformation.EgressBytes;
                    }
                    else throw;
                }
            }

            off += len;
        }