在分片之间迁移数据

时间:2015-01-12 16:11:43

标签: c# azure azure-sql-database azure-elastic-scale

对于我正在进行的项目,我们需要客户附近数据库中的客户数据。出于这个原因,我们采用了Microsoft的新Elastic Sc​​ale解决方案。这消除了分片的复杂性,并且仍然为您提供了在全球范围内扩展的能力。

目前我正面临一个相当重要的问题。我需要将数据从1个分片迁移到另一个分片。有一个示例应用程序(Merge / Split)可以执行某些操作,但它适用于Ranges(1..100,101..400等)。我正在处理的数据库与Guids一起工作,所以我们不能使用示例代码。

我自己创建了一个Move / Merge管理工具,但这里面临一个问题。 起初我想用ORM插入所有对象和依赖项。由于一些圆形键我不能轻易做到这一点。因此我现在正在创建一个SQL脚本。 SQL脚本大约130MB,只包含INSERT个命令。

所有这一切都必须在1个事务中完成,因为您不希望迁移完成一半。如果出现错误,应该回滚所有内容。

运行这个130MB的脚本会给我一些错误。我的本地开发机器和SQL Azure我的内存不足。 SQL Azure:

  

缓冲池中没有足够的可用内存

和本地:

  

资源池“default”中没有足够的系统内存来运行此查询。

我已尝试禁用索引,因此不会在每个INSERT上重建。这没有解决任何问题。

有关如何进行的任何建议?我无法真正拆分脚本,因为所有数据必须一次INSERT。我认为SSIS包不是一种选择。

创建我自己的数据库事务系统似乎有很多过度杀伤和容易出错。

除了INSERT脚本之外,我还需要在'旧'分片/数据库上执行DELETE脚本,所以我想解决方案也必须适用于此脚本。我希望在1个事务中执行INSERTDELETE脚本,但在SQL Azure(分布式事务)上可能尚未实现。

1 个答案:

答案 0 :(得分:2)

Azure SQL DB Elastic Sc​​ale当前预览中的Split / Merge版本具有已知的限制,即它仅适用于范围分片映射。我假设您正在使用列表分片地图为您的guids。虽然我们目前正致力于在弹性比例预览的更新中提供对列表分片地图和分割/合并的支持,但有一种解决方法,我鼓励您试用。这种解决方法可能比编写自己的基础架构以便在分片之间进行数据移动更简单,并为您节省大量工作(希望如此)。

以下是我的建议:

  • 使用guid类型的范围分片地图替换列表分片地图。
  • 将数据中的每个guid设为单个范围:使用guid值本身作为左边界和 使用在其二进制表示中递增1的guid值作为其右边界(请记住右边界是独占的,而左边是包含的)。您可以使用ShardKey类的RawKey属性轻松检索左边界点的二进制表示。
  • 将您的拆分/合并服务指向新的范围分片地图。
  • 在范围分片地图上使用分割/合并的分片移动操作,将给定的guid从一个分片移动到另一个分片。

让我知道这是如何运作的。如果你遇到麻烦 - 特别是在增加guid的时候 - 请给我一个关于twte(at)microsoft(dot)com的大喊。

最佳, 托

这是一段代码,可以帮助您增加guid值。

    static void CreateMappings()
    {
        ShardKey guid1 = new ShardKey(new Guid("<yourgui1d>"));
        ShardKey guid2 = new ShardKey(new Guid("<yourguid2>"));

        ShardKey guid1_next = NextShardKeyForGuid(guid1);
        ShardKey guid2_next = NextShardKeyForGuid(guid2);

        _map.CreateRangeMapping(new Range<Guid>(guid1.GetValue<Guid>(), guid1_next.GetValue<Guid>()), _shard1);
        _map.CreateRangeMapping(new Range<Guid>(guid2.GetValue<Guid>(), guid2_next.GetValue<Guid>()), _shard2);
    }

    static ShardKey NextShardKeyForGuid(ShardKey shardkey)
    {
        int len = 16;
        byte[] b = new byte[len];

        shardkey.RawValue.CopyTo(b, 0);

        while (--len >= 0 && ++b[len] == 0) ;

        // Treat overflow if the current key's value is the maximum in the domain
        if (len < 0)
        {
            return new ShardKey(ShardKeyType.Guid, null);
        }
        else
        {
            return ShardKey.FromRawValue(ShardKeyType.Guid, b);
        }
    }
}