Windows Azure表存储行大小限制小于规定的1MB



我使用以下资源对表存储及其大小限制、开销等进行了大量研究:

  • http://blogs.msdn.com/b/windowsazurestorage/archive/2010/07/09/understanding-windows-azure-storage-billing-bandwidth-transactions-and-capacity.aspx
  • http://msdn.microsoft.com/en-us/library/dd179338.aspx

使用这些信息,我编写了一些代码来有效地跨多个属性存储二进制数据,计算任何行和属性开销,并保持在64KB属性限制和1MB行限制内。

不幸的是,它就是不起作用。作为一个例子,存储大约0.5MB会返回一个400 Bad Request,表示实体太大了——我不明白为什么它会被给予1MB的行大小限制。

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
  <code>EntityTooLarge</code>
  <message xml:lang="en-GB">The entity is larger than allowed by the Table Service.</message>
</error>

我一直在使用的代码是相当直接的,但我可能在估计开销时犯了错误-但是我怀疑它会偏离100%的数据大小。

class Program
{
    static void Main(string[] args)
    {
        var client = CloudStorageAccount.DevelopmentStorageAccount.CreateCloudTableClient();
        var table = client.GetTableReference("sometable");
        table.CreateIfNotExists();
        const int rowOverhead = 4;
        const int maxRowSize = 1024 * 1024; // 1MB row size limit
        const int maxProperties = 252; // 255 less 3 system properties
        const int maxPropertySize = 64 * 1024; // 64KB property size limit
        var stream = new MemoryStream(new byte[512 * 1024]); // 0.5MB of data
        var entity = new DynamicTableEntity("pk", "rk");
        var buffer = new byte[maxPropertySize];
        var keySize = (entity.PartitionKey.Length + entity.RowKey.Length) * 2;
        var used = rowOverhead + keySize;
        for (var i = 0; i < maxProperties + 1; i++)
        {
            if (i > maxProperties)
            {
                throw new ArgumentException(string.Format("You have exceeded the column limit of {0}.", maxProperties));
            }
            var name = string.Concat("d", i);
            var overhead = CalculatePropertyOverhead(name, EdmType.Binary);
            var read = stream.Read(buffer, 0, maxPropertySize - overhead);
            used += read + overhead;
            if (used > maxRowSize)
            {
                throw new ArgumentException(string.Format("You have exceeded the max row size of {0} bytes.", maxRowSize));
            }
            if (read > 0)
            {
                var data = new byte[read];
                Array.Copy(buffer, 0, data, 0, read);
                entity.Properties.Add(name, new EntityProperty(data));
            }
            else
            {
                break;
            }
        }
        Console.WriteLine("Total entity size: {0}", used);
        table.Execute(TableOperation.InsertOrReplace(entity));
    }
    static int CalculatePropertyOverhead(string name, EdmType type)
    {
        const int propertyOverhead = 8;
        int propertyNameSize = name.Length * 2;
        int propertyTypeSize;
        switch (type)
        {
            case EdmType.Binary:
            case EdmType.Int32:
            case EdmType.String:
                propertyTypeSize = 4;
                break;
            case EdmType.Boolean:
                propertyTypeSize = 1;
                break;
            case EdmType.DateTime:
            case EdmType.Double:
            case EdmType.Int64:
                propertyTypeSize = 8;
                break;
            case EdmType.Guid:
                propertyTypeSize = 16;
                break;
            default:
                throw new NotSupportedException();
        }
        return propertyOverhead + propertyNameSize + propertyTypeSize;
    }
}

任何帮助解释我错过了什么是感激!

谢谢,

这张

Mattias,您所指的限制是针对实际的存储服务,但您针对的是本地存储模拟器。模拟器使用本地SQL Server作为其后备存储,并且具有与实际存储服务不同的限制。有关更多信息,请参阅http://msdn.microsoft.com/en-us/library/windowsazure/gg433135.aspx,特别是这一行:

* The total size of a row in a table in the storage emulator is limited to less than 1 MB.

我认为kwill的回答是正确的。然而,它回避了一个问题,即实际的限制是什么。在我自己的代码中,我想在单个实体中打包尽可能多的字节,所以我遇到了实体限制和请求体限制。

在写了一些繁琐的代码之后,这是我的发现:

在存储模拟器上,最大实体大小似乎是基于分区键和/或行键(也可能是表名)。使用Azure文档中提供的实体大小计算,最大实体大小是大约393,250字节。

下面是我修改的代码:https://gist.github.com/joelverhagen/bca6e0f9ed8fa779fcabc5c2904505ae

我最好的猜测是模拟器的实体大小计算错误,这导致了这种差异。

我只是让我的代码通过检查存储URI的主机(127.0.0.1表示模拟器)来检测模拟器是否正在运行。

相关内容

  • 没有找到相关文章

最新更新