如何在Azure表存储中使用整数RowKeys?

enz*_*nzi 5 c# azure azure-storage

我有连续编号的实体,我想坚持使用Azure表服务,但RowKey列的类型是有问题的.实体的数量应该存储在RowKey列中,这样我就可以查询实体fast(PK = '..' && RowKey = 5),获取最新的实体(RowKey > 10)并查询某组实体(RowKey > 5 && RowKey < 10).

由于RowKey必须是一个字符串,因此低于比较是有问题的("100" < "11").我想过在数字前面加零(这样"100" > "011"),但我无法预测实体的数量(以及零的数量).

我知道我可以创建一个整数列,但是我会放弃索引的RowKey列的性能优势(另外我没有任何其他适合RowKey的信息).以前有人有这个问题吗?

Jam*_*mas 5

我有一个类似的问题,添加警告我还想支持RowKey按降序排序.在我的情况下,我不关心支持数万亿的可能值,因为我正确使用PartitionKey并在需要时使用作用域前缀来进一步细分RowKey(如"scope-id" - >"12-8374").

最后,我决定了enzi建议的一般方法的具体实现.我使用了Base64编码的修改版本,生成了一个四字符串,支持超过1600万个值,可以按升序或降序排序.这是代码,已经过单元测试但缺少范围检查/验证.

/// <summary>
/// Gets the four character string representation of the specified integer id.
/// </summary>
/// <param name="number">The number to convert</param>
/// <param name="ascending">Indicates whether the encoded number will be sorted ascending or descending</param>
/// <returns>The encoded string representation of the number</returns>
public static string NumberToId(int number, bool ascending = true)
{
    if (!ascending)
        number = 16777215 - number;

    return new string(new[] { 
        SixBitToChar((byte)((number & 16515072) >> 18)), 
        SixBitToChar((byte)((number & 258048) >> 12)), 
        SixBitToChar((byte)((number & 4032) >> 6)), 
        SixBitToChar((byte)(number & 63)) });
}

/// <summary>
/// Gets the numeric identifier represented by the encoded string.
/// </summary>
/// <param name="id">The encoded string to convert</param>
/// <param name="ascending">Indicates whether the encoded number is sorted ascending or descending</param>
/// <returns>The decoded integer id</returns>
public static int IdToNumber(string id, bool ascending = true)
{
    var number = ((int)CharToSixBit(id[0]) << 18) | ((int)CharToSixBit(id[1]) << 12) | ((int)CharToSixBit(id[2]) << 6) | (int)CharToSixBit(id[3]);

    return ascending ? number : -1 * (number - 16777215);
}

/// <summary>
/// Converts the specified byte (representing 6 bits) to the correct character representation.
/// </summary>
/// <param name="b">The bits to convert</param>
/// <returns>The encoded character value</returns>
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)] 
static char SixBitToChar(byte b)
{
    if (b == 0)
        return '!';
    if (b == 1)
        return '$';
    if (b < 12)
        return (char)((int)b - 2 + (int)'0');
    if (b < 38)
        return (char)((int)b - 12 + (int)'A');
    return (char)((int)b - 38 + (int)'a');
}

/// <summary>
/// Coverts the specified encoded character into the corresponding bit representation.
/// </summary>
/// <param name="c">The encoded character to convert</param>
/// <returns>The bit representation of the character</returns>
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)] 
static byte CharToSixBit(char c)
{
    if (c == '!')
        return 0;
    if (c == '$')
        return 1;
    if (c <= '9')
        return (byte)((int)c - (int)'0' + 2);
    if (c <= 'Z')
        return (byte)((int)c - (int)'A' + 12);
    return (byte)((int)c - (int)'a' + 38);
}
Run Code Online (Sandbox Code Playgroud)

您可以将false传递给升序参数,以确保编码值将以相反的方向排序.我选择了!和$来完成Base64集,因为它们对RowKey值有效.可以轻松修改此算法以支持其他字符,但我坚信较大的数字对RowKey值没有意义,因为必须有效地分割表存储键.以下是输出的一些示例:

0 - > !!!! asc&zzzz desc

1000 - > !! Dc asc&zzkL desc

2000 - > !! TE asc&zzUj desc

3000 - > !!是asc&zzF5 desc

4000 - > !! yU asc&zz $ T desc

5000 - >!$ C6 asc&zylr desc

6000 - >!$ Rk asc&zyWD desc

7000 - >!$ hM asc&zyGb desc

8000 - >!$ x!asc&zy0z desc

9000 - >!0Ac asc&zxnL desc