Claves de partición jerárquicas en Azure Cosmos DB

SE APLICA A: NoSQL

Azure Cosmos DB distribuye los datos entre particiones lógicas y físicas en función de las claves de partición para soportar el escalado horizontal. Mediante el uso de claves de partición jerárquicas (también llamadas subparticiones), puede configurar hasta una jerarquía de tres niveles para sus claves de partición para optimizar aún más la distribución de datos y para un mayor nivel de escalado.

Si usa claves sintéticas en la actualidad o tiene escenarios en los que las claves de partición pueden superar los 20 GB de datos, la subpartición puede ayudar. Si usa esta característica, los prefijos de clave de partición lógica pueden superar los 20 GB y 10 000 unidades de solicitud por segundo (RU/s). Las consultas por prefijo se enrutan eficazmente al subconjunto de particiones que contienen los datos.

Elija las claves de partición jerárquicas

Si tiene aplicaciones multiinquilino, se recomienda usar claves de partición jerárquicas. Las particiones jerárquicas le permiten escalar más allá del límite de clave de partición lógica de 20 GB. Si la clave de partición actual o una clave de partición única suelen alcanzar los 20 GB, las particiones jerárquicas son una excelente opción para la carga de trabajo.

Al elegir las claves de partición jerárquicas, es importante tener en cuenta los siguientes conceptos generales de partición:

  • Para todos los contenedores, cada nivel de la ruta de acceso completa (empezando por el primer nivel) de la clave de partición jerárquica debe:

    • Tener una cardinalidad alta. Las claves primera, segunda y tercera (si procede) de la partición jerárquica deben tener una amplia gama de valores posibles.
    • Distribuir el consumo de unidades de solicitud (RU) y el almacenamiento de datos uniformemente en todas las particiones lógicas. Esto garantiza una distribución uniforme del consumo de RU y el almacenamiento en las particiones físicas.
  • En el caso de cargas de trabajo de gran tamaño de lectura intensiva, se recomienda elegir claves de partición jerárquicas que aparezcan con frecuencia en las consultas. Por ejemplo, una carga de trabajo que ejecuta consultas con frecuencia para filtrar sesiones de usuario específicas en una aplicación multiinquilino puede beneficiarse de las claves de partición jerárquicas de TenantId, UserId y SessionId, en ese orden. Las consultas se pueden enrutar de manera eficaz solo a las particiones físicas pertinentes si se incluye la clave de partición en el predicado de filtro. Para obtener más información sobre la elección de las claves de partición para cargas de trabajo de lectura intensiva, consulta la descripción general de partición.

Ejemplo de caso de uso

Supongamos que tiene un escenario multiinquilino en el que almacena información de eventos para los usuarios de cada inquilino. La información de evento puede incluir repeticiones de eventos, entre las que se incluyen, entre otras, eventos de inicio de sesión, secuencia de clics o de pago.

En un escenario real, algunos inquilinos pueden hacerse grandes con miles de usuarios, mientras que los muchos otros inquilinos son más pequeños y tienen unos pocos usuarios. La creación de particiones mediante /TenantId podría llevar a superar el límite de almacenamiento de 20 GB de Azure Cosmos DB en una única partición lógica. La creación de particiones mediante /UserId hace todas las consultas en una partición cruzada de inquilinos. Ambos enfoques tienen desventajas significativas.

El uso de una clave de partición sintética que combina TenantId y UserId agrega complejidad a la aplicación. Además, las consultas de clave de partición sintética para un inquilino se siguen realizando entre particiones, a menos que todos los usuarios sean conocidos y se especifiquen de antemano.

Con las claves de partición jerárquicas, puede crear particiones primero en TenantId y, a continuación, en UserId. Si espera que la combinación TenantId y UserId genere particiones que superen los 20 GB, puede crear incluso particiones más abajo en otro nivel, como en SessionId. La profundidad general no puede superar tres niveles. Cuando una partición física supera los 50 GB de almacenamiento, Azure Cosmos DB divide automáticamente la partición física para que aproximadamente una mitad de los datos estén en una partición física y la otra mitad en la otra. De hecho, la subpartición significa que un único valor TenantId puede superar los 20 GB de datos y es posible que los datos de TenantId abarquen varias particiones físicas.

Las consultas que especifican TenantId, o TenantId y UserId, se enrutan de forma eficaz solo al subconjunto de particiones físicas que contienen los datos pertinentes. La especificación de la ruta de acceso de clave de partición con subpartición completa o prefijo evita eficazmente una consulta de distribución ramificada completa. Por ejemplo, si el contenedor tuviera 1000 particiones físicas, pero un valor TenantId específico solo estuviera en 5 particiones físicas, la consulta se dirigiría al menor número de particiones físicas relevantes.

Usar el id. de elemento en la jerarquía

Si el contenedor tiene una propiedad con una amplia gama de valores posibles, la propiedad es probable que sea una buena elección para el último nivel de la jerarquía. Un posible ejemplo de este tipo de propiedad es el ID del artículo. La propiedad del sistema id. de elemento existe en todos los elementos del contenedor. Agregar el identificador de elemento como otro nivel garantiza que se puede escalar más allá del límite de clave de partición lógica de 20 GB. Puede escalar más allá de este límite para el primer nivel o para el primer y segundo nivel de claves.

Por ejemplo, puede tener un contenedor para una carga de trabajo multiinquilino particionada por TenantId y UserId. Si es posible que una única combinación de TenantId y UserId supere los 20 GB, entonces se recomienda crear particiones mediante tres niveles de claves, y en los que la clave de tercer nivel tenga una alta cardinalidad. Un ejemplo de este escenario es si la clave de tercer nivel es un GUID que tiene una cardinalidad alta de forma natural. Es poco probable que la combinación de TenantId, UserId y un GUID supere los 20 GB, por lo que la combinación de TenantId y UserId puede escalar efectivamente más allá de los 20 GB.

Para obtener más información sobre el uso del id. de elemento como clave de partición, consulte la Introducción a la creación de particiones.

Introducción

Importante

Trabajar con contenedores que usan claves de partición jerárquicas solo se admite en las siguientes versiones del SDK. Debe usar el SDK compatible para crear nuevos contenedores con claves de partición jerárquicas y realizar operaciones de consulta o creación, lectura, actualización y eliminación (CRUD) de los datos. Si desea usar un SDK o un conector que no se admite actualmente, envíe una solicitud a nuestro foro de la comunidad.

Busque la versión preliminar más reciente de cada SDK compatible:

SDK Versiones compatibles Vínculo del administrador de paquetes
.NET SDK v3 >= 3.33.0 https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.33.0/
SDK de Java v4 >= 4.42.0 https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/cosmos/azure-cosmos/CHANGELOG.md#4420-2023-03-17/
JavaScript SDK v4 4.0.0 https://www.npmjs.com/package/@azure/cosmos/

Creación de un contenedor mediante claves de partición jerárquicas

Para empezar, cree un contenedor mediante una lista predefinida de rutas de acceso de clave de subpartición con hasta tres niveles de profundidad.

Puede crear un contenedor mediante una de estas opciones:

  • Azure portal
  • SDK
  • Plantilla del Administrador de recursos de Azure
  • Emulador de Azure Cosmos DB

Azure portal

La manera más sencilla de crear un contenedor y especificar claves de partición jerárquicas consiste en usar Azure Portal.

  1. Inicie sesión en Azure Portal.

  2. Vaya a la página de la cuenta de Azure Cosmos DB for NoSQL existente.

  3. En el menú de la izquierda, seleccione Explorador de datos.

    Screenshot that shows the page for a new Azure Cosmos DB for NoSQL account with the Data Explorer menu option highlighted.

  4. En Explorador de datos, seleccione la opción Nuevo contenedor.

    Screenshot of the New Container option within Data Explorer.

  5. En Nuevo contenedor, en Clave de partición, escriba /TenantId. Para los campos restantes, escriba cualquier valor que coincida con el escenario.

    Nota:

    Usamos /TenantId como ejemplo aquí. Puede especificar cualquier clave para el primer nivel al implementar claves de partición jerárquicas en contenedores propios.

  6. Seleccione dos veces Agregar clave de partición jerárquica.

    Screenshot of the button to add a new hierarchical partition key.

  7. Para los niveles segundo y tercero de la subpartición, introduzca /UserId y /SessionId, respectivamente.

    Screenshot of a list of three hierarchical partition keys.

  8. Seleccione Aceptar para crear el contenedor.

SDK

Al crear un contenedor mediante el SDK, defina una lista de rutas de acceso de clave de subpartición hasta tres niveles de profundidad. Use la lista de claves de subpartición al configurar las propiedades del nuevo contenedor.

// List of partition keys, in hierarchical order. You can have up to three levels of keys.
List<string> subpartitionKeyPaths = new List<string> { 
    "/TenantId",
    "/UserId",
    "/SessionId"
};

// Create a container properties object
ContainerProperties containerProperties = new ContainerProperties(
    id: "<container-name>",
    partitionKeyPaths: subpartitionKeyPaths
);

// Create a container that's subpartitioned by TenantId > UserId > SessionId
Container container = await database.CreateContainerIfNotExistsAsync(containerProperties, throughput: 400);

Plantillas del Administrador de recursos de Azure

La plantilla de Azure Resource Manager para un contenedor subparticionado es casi idéntica a la de un contenedor estándar. La única diferencia clave es el valor de la ruta de acceso properties/partitionKey. Para obtener más información sobre cómo crear una plantilla de Azure Resource Manager para un recurso de Azure Cosmos DB, consulte la documentación de plantillas de Azure Resource Manager para Azure Cosmos DB.

Configure el objeto partitionKey mediante los valores de la tabla siguiente para crear un contenedor subpartido:

Ruta de acceso Valor
paths Lista de claves de partición jerárquicas (máximo tres niveles de profundidad)
kind MultiHash
version 2

Ejemplo de definición de clave de partición

Por ejemplo, supongamos que tiene una clave de partición jerárquica compuesta por TenantId>UserId>SessionId. El objeto partitionKey se configuraría para incluir los tres valores de la propiedad paths, un valor kind de MultiHash y un valor version de 2.

partitionKey: {
  paths: [
    '/TenantId',
    '/UserId',
    '/SessionId'
  ]
  kind: 'MultiHash'
  version: 2
}

Para obtener más información sobre el objeto partitionKey, consulte la especificación ContainerPartitionKey.

Emulador de Azure Cosmos DB

Puede probar la característica de subpartición mediante la versión más reciente del emulador local para Azure Cosmos DB. Para habilitar la subpartición en el emulador, inicie el emulador desde el directorio de instalación con la marca /EnablePreview:

.\CosmosDB.Emulator.exe /EnablePreview

Advertencia

El emulador no admite actualmente todas las características de clave de partición jerárquica que admite el portal. El emulador no admite actualmente:

  • Uso de Data Explorer para crear contenedores con claves de partición jerárquica
  • Uso de Data Explorer para navegar e interactuar con elementos mediante claves de partición jerárquica

Para obtener más información, consulte Emulador de Azure Cosmos DB.

Uso de los SDK para trabajar con contenedores que tienen claves de partición jerárquicas

Cuando tenga un contenedor que tenga claves de partición jerárquica, use las versiones especificadas anteriormente de los SDK de .NET o Java para realizar operaciones y ejecutar consultas en ese contenedor.

Adición de un elemento a un contenedor

Hay dos opciones para agregar un nuevo elemento a un contenedor con claves de partición jerárquicas habilitadas:

  • Extracción automática
  • Especificación manual de la ruta de acceso

Extracción automática

Si pasa un objeto con el conjunto de valores de clave de partición, el SDK puede extraer automáticamente la ruta de acceso de clave de partición completa.

// Create a new item
UserSession item = new UserSession()
{
    id = "f7da01b0-090b-41d2-8416-dacae09fbb4a",
    TenantId = "Microsoft",
    UserId = "8411f20f-be3e-416a-a3e7-dcd5a3c1f28b",
    SessionId = "0000-11-0000-1111"
};

// Pass in the object, and the SDK automatically extracts the full partition key path
ItemResponse<UserSession> createResponse = await container.CreateItemAsync(item);

Especificación manual de la ruta de acceso

La clase PartitionKeyBuilder del SDK puede construir un valor para una ruta de acceso de clave de partición jerárquica definida previamente. Use esta clase al agregar un nuevo elemento a un contenedor que tenga habilitada la subpartición.

Sugerencia

A gran escala, el rendimiento puede mejorar si se especifica la ruta de acceso de clave de partición completa incluso si el SDK puede extraer la ruta de acceso del objeto.

// Create a new item object
PaymentEvent item = new PaymentEvent()
{
    id = Guid.NewGuid().ToString(),
    TenantId = "Microsoft",
    UserId = "8411f20f-be3e-416a-a3e7-dcd5a3c1f28b",
    SessionId = "0000-11-0000-1111"
};

// Specify the full partition key path when creating the item
PartitionKey partitionKey = new PartitionKeyBuilder()
            .Add(item.TenantId)
            .Add(item.UserId)
            .Add(item.SessionId)
            .Build();

// Create the item in the container
ItemResponse<PaymentEvent> createResponse = await container.CreateItemAsync(item, partitionKey);

Búsqueda de clave y valor (lectura puntual) de un elemento

Las búsquedas de clave y valor (lecturas puntuales) se realizan de forma similar a un contenedor no particionado. Por ejemplo, supongamos que tiene una clave de partición jerárquica que consta de TenantId>UserId>SessionId. El identificador único del elemento es un GUID. Está representado como una cadena que actúa como identificador de transacción de documento único. Para realizar una lectura puntual en un solo elemento, pase la propiedad id del elemento y el valor completo de la clave de partición, incluidos los tres componentes de la ruta de acceso.

// Store the unique identifier
string id = "f7da01b0-090b-41d2-8416-dacae09fbb4a";

// Build the full partition key path
PartitionKey partitionKey = new PartitionKeyBuilder()
    .Add("Microsoft") //TenantId
    .Add("8411f20f-be3e-416a-a3e7-dcd5a3c1f28b") //UserId
    .Add("0000-11-0000-1111") //SessionId
    .Build();

// Perform a point read
ItemResponse<UserSession> readResponse = await container.ReadItemAsync<UserSession>(
    id,
    partitionKey
);

Ejecución de una consulta

El código del SDK que se usa para ejecutar una consulta en un contenedor con particiones secundarias es idéntico a ejecutar una consulta en un contenedor no particionado.

Cuando la consulta especifica todos los valores de las claves de partición en el filtro WHERE o en un prefijo de la jerarquía de claves, el SDK enruta automáticamente la consulta a las particiones físicas correspondientes. Las consultas que proporcionan solo el "centro" de la jerarquía son consultas entre particiones.

Por ejemplo, considere una clave de partición jerárquica compuesta por TenantId>UserId>SessionId. Los componentes del filtro de la consulta determinan si la consulta es una consulta de partición única, una consulta de partición cruzada de destino o una consulta de distribución ramificada.

Consultar Enrutamiento
SELECT * FROM c WHERE c.TenantId = 'Microsoft' AND c.UserId = '8411f20f-be3e-416a-a3e7-dcd5a3c1f28b' AND c.SessionId = '0000-11-0000-1111' Enrutada a la única partición lógica y física que contiene los datos de los valores especificados de TenantId, UserId y SessionId.
SELECT * FROM c WHERE c.TenantId = 'Microsoft' AND c.UserId = '8411f20f-be3e-416a-a3e7-dcd5a3c1f28b' Enrutada solo al subconjunto de destino de particiones lógicas y físicas que contienen datos para los valores especificados de TenantId y UserId. Esta consulta es una consulta entre particiones dirigida que devuelve datos de un usuario específico del inquilino.
SELECT * FROM c WHERE c.TenantId = 'Microsoft' Enrutada solo al subconjunto de destino de particiones lógicas y físicas que contienen datos para el valor especificado de TenantId. Esta consulta es una consulta entre particiones dirigida que devuelve datos para todos los usuarios de un inquilino.
SELECT * FROM c WHERE c.UserId = '8411f20f-be3e-416a-a3e7-dcd5a3c1f28b' Enrutada a todas las particiones físicas, lo que da lugar a una consulta entre particiones de distribución ramificada.
SELECT * FROM c WHERE c.SessionId = '0000-11-0000-1111' Enrutada a todas las particiones físicas, lo que da lugar a una consulta entre particiones de distribución ramificada.

Consulta de partición única en un contenedor con particiones secundarias

Este es un ejemplo de ejecución de una consulta que incluye todos los niveles de subparticiones, lo que la convierte eficazmente en una consulta de partición única.

// Define a single-partition query that specifies the full partition key path
QueryDefinition query = new QueryDefinition(
    "SELECT * FROM c WHERE c.TenantId = @tenant-id AND c.UserId = @user-id AND c.SessionId = @session-id")
    .WithParameter("@tenant-id", "Microsoft")
    .WithParameter("@user-id", "8411f20f-be3e-416a-a3e7-dcd5a3c1f28b")
    .WithParameter("@session-id", "0000-11-0000-1111");

// Retrieve an iterator for the result set
using FeedIterator<PaymentEvent> results = container.GetItemQueryIterator<PaymentEvent>(query);

while (results.HasMoreResults)
{
    FeedResponse<UserSession> resultsPage = await resultSet.ReadNextAsync();
    foreach(UserSession result in resultsPage)
    {
        // Process result
    }
}

Consulta de varias particiones dirigida en un contenedor con particiones secundarias

Este es un ejemplo de una consulta que incluye un subconjunto de los niveles de subparticiones lo que la convierte eficazmente en una consulta destinada a varias particiones.

// Define a targeted cross-partition query specifying prefix path[s]
QueryDefinition query = new QueryDefinition(
    "SELECT * FROM c WHERE c.TenantId = @tenant-id")
    .WithParameter("@tenant-id", "Microsoft")

// Retrieve an iterator for the result set
using FeedIterator<PaymentEvent> results = container.GetItemQueryIterator<PaymentEvent>(query);

while (results.HasMoreResults)
{
    FeedResponse<UserSession> resultsPage = await resultSet.ReadNextAsync();
    foreach(UserSession result in resultsPage)
    {
        // Process result
    }
}

Limitaciones y problemas conocidos

  • Trabajar con contenedores que usan claves de partición jerárquicas solo se admite en el SDK v3 de .NET y el SDK v4 de Java, y en la versión preliminar del SDK de JavaScript. Debe usar el SDK compatible para crear nuevos contenedores que tengan claves de partición jerárquicas y realizar operaciones CRUD o consultas en los datos. La compatibilidad con otros SDK, incluido Python, no está disponible actualmente.
  • Existen limitaciones con varios conectores de Azure Cosmos DB (por ejemplo, con Azure Data Factory).
  • Solo puede especificar claves de partición jerárquicas de hasta tres capas en profundidad.
  • Actualmente, las claves de partición jerárquica solo se pueden habilitar en contenedores nuevos. Debe establecer rutas de acceso de clave de partición en el momento de la creación del contenedor y no puede cambiarlas más adelante. Para usar particiones jerárquicas en contenedores existentes, cree un nuevo contenedor con las claves de partición jerárquicas establecidas y mover los datos mediante trabajos de copia de contenedores.
  • Actualmente, las claves de partición jerárquicas solo son compatibles con las cuentas de API para NoSQL. Actualmente no se admiten las API de MongoDB ni de Cassandra.
  • No se admiten actualmente claves de partición jerárquicas con la característica Permisos. No se puede asignar un permiso a un prefijo parcial de la ruta de acceso de la clave de partición jerárquica. Los permisos solo se pueden asignar a toda la ruta de acceso de la clave de partición lógica. Por ejemplo, si ha particionado por TenantId, >UserId, no puede asignar un permiso que sea para un valor específico de TenantId. Sin embargo, puede asignar un permiso para una clave de partición si especifica el valor de TenantId y "UserId".

Pasos siguientes