将未分区的容器迁移到已分区的容器Migrate non-partitioned containers to partitioned containers

Azure Cosmos DB 支持创建不带分区键的容器。Azure Cosmos DB supports creating containers without a partition key. 目前可以使用 Azure CLI 以及版本低于或等于 2.x 的 Azure Cosmos DB SDK(.Net、Java、NodeJs)创建未分区的容器。Currently you can create non-partitioned containers by using Azure CLI and Azure Cosmos DB SDKs (.Net, Java, NodeJs) that have a version less than or equal to 2.x. 无法使用 Azure 门户创建未分区的容器。You cannot create non-partitioned containers using the Azure portal. 但是,此类未分区容器不具有弹性,并且其存储容量固定为 20 GB,吞吐量限制为 10K RU/秒。However, such non-partitioned containers aren't elastic and have fixed storage capacity of 20 GB and throughput limit of 10K RU/s.

未分区的容器已经过时,应将现有的未分区容器迁移到已分区的容器,以扩展存储量和吞吐量。The non-partitioned containers are legacy and you should migrate your existing non-partitioned containers to partitioned containers to scale storage and throughput. Azure Cosmos DB 提供系统定义的机制用于将未分区的容器迁移到已分区的容器。Azure Cosmos DB provides a system defined mechanism to migrate your non-partitioned containers to partitioned containers. 本文档介绍如何将所有现有的未分区容器自动迁移到已分区的容器。This document explains how all the existing non-partitioned containers are auto-migrated into partitioned containers. 仅当使用的是支持所有语言的 V3 版 SDK 时,才能利用自动迁移功能。You can take advantage of the auto-migration feature only if you are using the V3 version of SDKs in all the languages.

备注

目前,无法使用本文档中所述的步骤迁移 Azure Cosmos DB MongoDB 和 Gremlin API 帐户。Currently, you cannot migrate Azure Cosmos DB MongoDB and Gremlin API accounts by using the steps described in this document.

使用系统定义的分区键迁移容器Migrate container using the system defined partition key

为了支持迁移,Azure Cosmos DB 将在没有分区键的所有容器中提供一个名为 /_partitionkey 的系统定义分区键。To support the migration, Azure Cosmos DB provides a system defined partition key named /_partitionkey on all the containers that don't have a partition key. 迁移容器后,无法更改分区键定义。You cannot change the partition key definition after the containers are migrated. 例如,已迁移到分区容器的容器的定义如下所示:For example, the definition of a container that is migrated to a partitioned container will be as follows:

{
    "Id": "CollId" 
  "partitionKey": {
    "paths": [
      "/_partitionKey"
    ],
    "kind": "Hash"
  },
}

迁移容器后,可以通过填充 _partitionKey 属性以及其他文档属性来创建文档。After the container is migrated, you can create documents by populating the _partitionKey property along with the other properties of the document. _partitionKey 属性表示文档的分区键。The _partitionKey property represents the partition key of your documents.

选择适当的分区键非常重要,这样才能以最佳方式利用预配的吞吐量。Choosing the right partition key is important to utilize the provisioned throughput optimally. 有关详细信息,请参阅如何选择分区键一文。For more information, see how to choose a partition key article.

备注

仅当使用的是支持所有语言的最新/V3 版 SDK 时,才能利用系统定义的分区键。You can take advantage of system defined partition key only if you are using the latest/V3 version of SDKs in all the languages.

以下示例代码演示如何使用系统定义的分区键创建一个文档,然后读取该文档:The following example shows a sample code to create a document with the system defined partition key and read that document:

文档的 JSON 表示形式JSON representation of the document

DeviceInformationItem = new DeviceInformationItem
{
   "id": "elevator/PugetSound/Building44/Floor1/1",
   "deviceId": "3cf4c52d-cc67-4bb8-b02f-f6185007a808",
   "_partitionKey": "3cf4c52d-cc67-4bb8-b02f-f6185007a808"
} 

public class DeviceInformationItem
{
    [JsonProperty(PropertyName = "id")]
    public string Id { get; set; }

    [JsonProperty(PropertyName = "deviceId")]
    public string DeviceId { get; set; }

    [JsonProperty(PropertyName = "_partitionKey", NullValueHandling = NullValueHandling.Ignore)]
    public string PartitionKey {get {return this.DeviceId; set; }
}

CosmosContainer migratedContainer = database.Containers["testContainer"];

DeviceInformationItem deviceItem = new DeviceInformationItem() {
  Id = "1234",
  DeviceId = "3cf4c52d-cc67-4bb8-b02f-f6185007a808"
}

ItemResponse<DeviceInformationItem > response = 
  await migratedContainer.CreateItemAsync<DeviceInformationItem>(
    deviceItem.PartitionKey, 
    deviceItem
  );

// Read back the document providing the same partition key
ItemResponse<DeviceInformationItem> readResponse = 
  await migratedContainer.ReadItemAsync<DeviceInformationItem>( 
    partitionKey:deviceItem.PartitionKey, 
    id: device.Id
  );

有关完整示例,请参阅 .Net 示例 GitHub 存储库。For the complete sample, see the .Net samples GitHub repository.

迁移文档Migrate the documents

尽管容器定义已通过分区键属性得到增强,但容器中的文档不会自动迁移。While the container definition is enhanced with a partition key property, the documents within the container aren't auto migrated. 这意味着,系统分区键属性 /_partitionKey 路径不会自动添加到现有的文档。Which means the system partition key property /_partitionKey path is not automatically added to the existing documents. 需要通过读取创建的不带分区键的文档将现有文档重新分区,然后使用文档中的 _partitionKey 属性重新写入这些文档。You need to repartition the existing documents by reading the documents that were created without a partition key and rewrite them back with _partitionKey property in the documents.

访问不带分区键的文档Access documents that don't have a partition key

应用程序可以使用名为“PartitionKey.None”(这是未迁移的文档的值)的特殊系统属性来访问不带分区键的现有文档。Applications can access the existing documents that don't have a partition key by using the special system property called "PartitionKey.None", this is the value of the non-migrated documents. 可以在所有 CRUD 和查询操作中使用此属性。You can use this property in all the CRUD and query operations. 以下示例演示如何从 NonePartitionKey 读取单个文档。The following example shows a sample to read a single Document from the NonePartitionKey.

CosmosItemResponse<DeviceInformationItem> readResponse = 
await migratedContainer.Items.ReadItemAsync<DeviceInformationItem>( 
  partitionKey: PartitionKey.None, 
  id: device.Id
); 

有关如何将文档重新分区的完整示例,请参阅 .Net 示例 GitHub 存储库。For the complete sample on how to repartition the documents, see the .Net samples GitHub repository.

与 SDK 的兼容性Compatibility with SDKs

旧版 Azure Cosmos DB SDK(例如 V2.x.x 和 V1.x.x)不支持系统定义的分区键属性。Older version of Azure Cosmos DB SDKs such as V2.x.x and V1.x.x don't support the system defined partition key property. 因此,从旧版 SDK 读取容器定义时,读取结果不包含任何分区键定义,这些容器的行为与以前完全相同。So, when you read the container definition from an older SDK, it doesn't contain any partition key definition and these containers will behave exactly as before. 使用旧版 SDK 生成的应用程序将继续使用未分区的容器,就如同未发生任何更改一样。Applications that are built with the older version of SDKs continue to work with non-partitioned as is without any changes.

如果迁移的容器已由最新/V3 版 SDK 使用,当你开始在新文档中填充系统定义的分区键时,不再可以从旧版 SDK 访问(读取、更新、删除、查询)此类文档。If a migrated container is consumed by the latest/V3 version of SDK and you start populating the system defined partition key within the new documents, you cannot access (read, update, delete, query) such documents from the older SDKs anymore.

已知问题Known issues

使用 V3 SDK 查询未通过分区键插入的项的计数可能涉及更高的吞吐量消耗Querying for the count of items that were inserted without a partition key by using V3 SDK may involve higher throughput consumption

如果从 V3 SDK 中查询使用 V2 SDK 插入的项,或查询通过带 PartitionKey.None 参数的 V3 SDK 来插入的项,则在 FeedOptions 中提供 PartitionKey.None 参数时,计数查询可能会消耗更多的 RU/秒。If you query from the V3 SDK for the items that are inserted by using V2 SDK, or the items inserted by using the V3 SDK with PartitionKey.None parameter, the count query may consume more RU/s if the PartitionKey.None parameter is supplied in the FeedOptions. 如果未使用分区键插入其他项,建议不要提供 PartitionKey.None 参数。We recommend that you don't supply the PartitionKey.None parameter if no other items are inserted with a partition key.

如果使用不同的分区键值插入新项,则通过在 FeedOptions 中传递适当的密钥来查询此类项计数不会有任何问题。If new items are inserted with different values for the partition key, querying for such item counts by passing the appropriate key in FeedOptions will not have any issues. 插入具有分区键的新文档后,如果只需要查询不带分区键值的文档计数,则该查询可能会再次产生更高的 RU/秒(类似于常规分区集合)。After inserting new documents with partition key, if you need to query just the document count without the partition key value, that query may again incur higher RU/s similar to the regular partitioned collections.

后续步骤Next steps