Chiavi di partizione gerarchiche in Azure Cosmos DB

SI APPLICA A: NoSQL

Azure Cosmos DB distribuisce i dati tra partizioni logiche e fisiche in base alle chiavi di partizione per supportare il ridimensionamento orizzontale. Usando chiavi di partizione gerarchica (denominate anche subpartitoning), è possibile configurare fino a una gerarchia a tre livelli per le chiavi di partizione per ottimizzare ulteriormente la distribuzione dei dati e per un livello superiore di scalabilità.

Se si usano attualmente chiavi sintetiche o se si hanno scenari in cui le chiavi di partizione possono superare i 20 GB di dati, la sottopartizione può essere utile. Se si usa questa funzionalità, i prefissi della chiave di partizione logica possono superare 20 GB e 10.000 unità richiesta al secondo (UR/sec). Le query in base al prefisso vengono instradate in modo efficiente al subset di partizioni che contengono i dati.

Scegliere le chiavi di partizione gerarchica

Se si dispone di applicazioni multi-tenant, è consigliabile usare chiavi di partizione gerarchica. Le partizioni gerarchiche consentono di passare oltre il limite di chiavi di partizione logica di 20 GB. Se la chiave di partizione corrente o se una singola chiave di partizione raggiunge spesso 20 GB, le partizioni gerarchiche rappresentano una scelta ottimale per il carico di lavoro.

Quando si scelgono le chiavi di partizione gerarchica, è importante tenere presenti i concetti generali di partizionamento seguenti:

  • Per tutti i contenitori, ogni livello del percorso completo (a partire dal primo livello) della chiave di partizione gerarchica deve:

    • Avere una cardinalità elevata. La prima, la seconda e la terza chiave (se applicabile) della partizione gerarchica devono avere tutti un'ampia gamma di valori possibili.
    • Distribuire in modo uniforme l'utilizzo dell'unità richiesta (UR) e l'archiviazione dei dati in tutte le partizioni logiche. Questa ripartizione garantisce anche la distribuzione uniforme dell'utilizzo di UR e dello spazio di archiviazione tra le partizioni fisiche.
  • Per carichi di lavoro di grandi dimensioni e con intensa attività di lettura, è consigliabile scegliere chiavi di partizione gerarchiche che vengono visualizzate di frequente nelle query. Ad esempio, un carico di lavoro che esegue spesso query per filtrare le sessioni utente specifiche in un'applicazione multi-tenant può trarre vantaggio dalle chiavi di partizione gerarchiche di TenantId, UserIde SessionId, in tale ordine. Affinché le query vengano instradate in modo efficiente solo alle partizioni fisiche pertinenti, includere la chiave di partizione nel predicato del filtro. Per altre informazioni sulla scelta delle chiavi di partizione per carichi di lavoro con utilizzo elevato di lettura, vedere la panoramica del partizionamento.

Esempio di caso d'uso

Si supponga di avere uno scenario multi-tenant in cui archiviare le informazioni sugli eventi per gli utenti in ogni tenant. Le informazioni sull'evento potrebbero avere occorrenze di eventi, tra cui, ad esempio, l'accesso, clickstream o gli eventi di pagamento.

In uno scenario reale, alcuni tenant possono crescere di grandi dimensioni, con migliaia di utenti, mentre gli altri tenant sono più piccoli e hanno alcuni utenti. Il partizionamento da /TenantId può causare il superamento del limite di archiviazione di Azure Cosmos DB di 20 GB in una singola partizione logica. Il partizionamento esegue /UserId tutte le query in una partizione tra tenant. Entrambi gli approcci presentano svantaggi significativi.

Uso di una chiave di partizione sintetica che combina TenantId e UserId aggiunge complessità all'applicazione. Inoltre, le query di chiave di partizione sintetica per un tenant sono ancora tra partizioni, a meno che tutti gli utenti non siano noti e specificati in anticipo.

Con le chiavi di partizione gerarchica, è possibile partizionare prima in TenantIde quindi in UserId. Se si prevede che la TenantId combinazione e UserId producano partizioni che superano i 20 GB, è anche possibile partizionare ulteriormente fino a un altro livello, ad esempio in SessionId. La profondità complessiva non può superare tre livelli. Quando una partizione fisica supera i 50 GB di spazio di archiviazione, Azure Cosmos DB divide automaticamente la partizione fisica in modo che circa la metà dei dati si trova in una partizione fisica e la metà si trova nell'altra. In effetti, la sottopartizione indica che un singolo TenantId valore può superare i 20 GB di dati ed è possibile che TenantId i dati si estendono su più partizioni fisiche.

Le query che specificano TenantId, o entrambe TenantId e UserId, vengono instradate in modo efficiente solo al subset di partizioni fisiche che contengono i dati pertinenti. Se si specifica il percorso della chiave di partizione completa o con prefisso, è possibile evitare in modo efficace una query full fan-out. Ad esempio, se il contenitore aveva 1.000 partizioni fisiche, ma un valore specifico TenantId era solo su 5 partizioni fisiche, la query verrà instradata al numero inferiore di partizioni fisiche pertinenti.

Usare l'ID elemento nella gerarchia

Se il contenitore ha una proprietà con una vasta gamma di valori possibili, è probabile che la proprietà sia una scelta ottimale per la chiave di partizione per l'ultimo livello della gerarchia. Un esempio possibile di questo tipo di proprietà è l'ID elemento. L'ID elemento di una proprietà di sistema è presente in ogni elemento di un contenitore. L'aggiunta dell'ID elemento come un altro livello garantisce la scalabilità oltre il limite di chiavi di partizione logica di 20 GB. È possibile superare questo limite per il primo livello o per i primi e i secondi livelli di chiavi.

Ad esempio, potrebbe essere disponibile un contenitore per un carico di lavoro multi-tenant partizionato da TenantId e UserId. Se è possibile una singola combinazione di TenantId e UserId superare i 20 GB, è consigliabile partizionare usando tre livelli di chiavi e in cui la chiave di terzo livello ha cardinalità elevata. Un esempio di questo scenario è se la chiave di terzo livello è un GUID con cardinalità naturalmente elevata. È improbabile che la combinazione di TenantId, UserIde un GUID superi i 20 GB, in modo che la combinazione di TenantId e UserId possa essere ridimensionata in modo efficace oltre 20 GB.

Per altre informazioni sull'uso dell'ID elemento come chiave di partizione, vedere la panoramica del partizionamento.

Operazioni preliminari

Importante

L'uso di contenitori che usano chiavi di partizione gerarchica è supportato solo nelle versioni dell'SDK seguenti. È necessario usare un SDK supportato per creare nuovi contenitori con chiavi di partizione gerarchica e per eseguire operazioni di creazione, lettura, aggiornamento ed eliminazione (CRUD) o di query sui dati. Se si vuole usare un SDK o un connettore attualmente non supportato, inviare una richiesta nel forum della community.

Trovare la versione di anteprima più recente di ogni SDK supportato:

SDK Versioni supportate Collegamento di Gestione pacchetti
.NET SDK v3 >= 3.33.0 https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.33.0/
Java SDK 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/
Python SDK >= 4.6.0 https://pypi.org/project/azure-cosmos/4.6.0/

Creare un contenitore usando chiavi di partizione gerarchica

Per iniziare, creare un nuovo contenitore usando un elenco predefinito di percorsi chiave di partizionamento fino a tre livelli di profondità.

È possibile creare un nuovo contenitore usando una di queste opzioni:

  • Azure portal
  • SDK
  • Modello di Azure Resource Manager
  • Emulatore di Azure Cosmos DB

Azure portal

Il modo più semplice per creare un contenitore e specificare chiavi di partizione gerarchica consiste nell'usare il portale di Azure.

  1. Accedere al portale di Azure.

  2. Passare alla pagina esistente dell'account Azure Cosmos DB per NoSQL.

  3. Nel menu a sinistra selezionare Esplora dati.

    Screenshot che mostra la pagina per un nuovo account Azure Cosmos DB per NoSQL con l'opzione di menu Esplora dati evidenziata.

  4. In Esplora dati selezionare l'opzione Nuovo contenitore.

    Screenshot dell'opzione Nuovo contenitore all'interno di Esplora dati.

  5. In Nuovo contenitore immettere per Chiave di /TenantIdpartizione. Per i campi rimanenti, immettere qualsiasi valore corrispondente allo scenario.

    Nota

    Qui viene usato /TenantId come esempio. È possibile specificare qualsiasi chiave per il primo livello quando si implementano chiavi di partizione gerarchica nei propri contenitori.

  6. Selezionare Aggiungi chiave di partizione gerarchica due volte.

    Screenshot del pulsante per aggiungere una nuova chiave di partizione gerarchica.

  7. Per i secondi e i terzi livelli di sottopartizione, immettere /UserId e /SessionId rispettivamente.

    Screenshot di un elenco di tre chiavi di partizione gerarchica.

  8. Seleziona OK per creare il contenitore.

SDK

Quando si crea un nuovo contenitore usando l'SDK, definire un elenco di percorsi chiave di partizionamento fino a tre livelli di profondità. Usare l'elenco di chiavi di sottopartizione quando si configurano le proprietà del nuovo contenitore.

// 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);

Modelli di Azure Resource Manager

Il modello di Azure Resource Manager per un contenitore partizionato è quasi identico a un contenitore standard. L'unica differenza chiave è il valore del properties/partitionKey percorso. Per altre informazioni sulla creazione di un modello di Azure Resource Manager per una risorsa di Azure Cosmos DB, vedere le informazioni di riferimento sul modello di Azure Resource Manager per Azure Cosmos DB.

Configurare l'oggetto partitionKey usando i valori nella tabella seguente per creare un contenitore partizionato:

Percorso Valore
paths Elenco di chiavi di partizione gerarchica (massimo tre livelli di profondità)
kind MultiHash
version 2

Definizione di chiave di partizione di esempio

Si supponga, ad esempio, di avere una chiave di partizione gerarchica composta da TenantIdSessionId>UserId>. L'oggetto partitionKey verrà configurato in modo da includere tutti e tre i valori nella paths proprietà , un kind valore di MultiHashe un version valore di 2.

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

Per altre informazioni sull'oggetto partitionKey , vedere la specifica ContainerPartitionKey.

Emulatore di Azure Cosmos DB

È possibile testare la funzionalità di sottopartizione usando la versione più recente dell'emulatore locale per Azure Cosmos DB. Per abilitare la sottoparizione nell'emulatore, avviare l'emulatore dalla directory di installazione con il /EnablePreview flag :

.\CosmosDB.Emulator.exe /EnablePreview

Avviso

L'emulatore attualmente non supporta tutte le funzionalità della chiave di partizione hiearchical come portale. L'emulatore attualmente non supporta:

  • Uso del Esplora dati per creare contenitori con chiavi di partizione gerarchica
  • Uso del Esplora dati per passare e interagire con gli elementi usando chiavi di partizione gerarchica

Per altre informazioni, vedere Emulatore di Azure Cosmos DB.

Usare gli SDK per usare i contenitori con chiavi di partizione gerarchiche

Quando si dispone di un contenitore con chiavi di partizione gerarchiche, usare le versioni specificate in precedenza degli SDK .NET o Java per eseguire operazioni ed eseguire query su tale contenitore.

Aggiungere un elemento a un contenitore

Sono disponibili due opzioni per aggiungere un nuovo elemento a un contenitore con chiavi di partizione gerarchica abilitate:

  • Estrazione automatica
  • Specificare manualmente il percorso

Estrazione automatica

Se si passa un oggetto con il valore della chiave di partizione impostato, l'SDK può estrarre automaticamente il percorso completo della chiave di partizione.

// 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);

Specificare manualmente il percorso

La PartitionKeyBuilder classe nell'SDK può costruire un valore per un percorso di chiave di partizione gerarchico definito in precedenza. Usare questa classe quando si aggiunge un nuovo elemento a un contenitore in cui è abilitata la sottopartizione.

Suggerimento

Su larga scala, le prestazioni potrebbero essere migliorate se si specifica il percorso completo della chiave di partizione, anche se l'SDK può estrarre il percorso dall'oggetto.

// 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);

Eseguire una ricerca chiave/valore (lettura punto) di un elemento

Le ricerche chiave/valore (letture di punti) vengono eseguite in modo simile a un contenitore non partizionato. Si supponga, ad esempio, di avere una chiave di TenantId>>UserIdSessionIdpartizione gerarchica costituita da . L'identificatore univoco per l'elemento è un GUID. Viene rappresentato come stringa che funge da identificatore univoco della transazione del documento. Per eseguire un punto letto su un singolo elemento, passare la id proprietà dell'elemento e il valore completo per la chiave di partizione, inclusi tutti e tre i componenti del percorso.

// 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
);

Eseguire una query

Il codice SDK usato per eseguire una query in un contenitore sottopartizionato è identico all'esecuzione di una query in un contenitore non partizionato.

Quando la query specifica tutti i valori delle chiavi di partizione nel WHERE filtro o in un prefisso della gerarchia di chiavi, l'SDK instrada automaticamente la query alle partizioni fisiche corrispondenti. Le query che forniscono solo il "centro" della gerarchia sono query tra partizioni.

Si consideri, ad esempio, una chiave di partizione gerarchica composta da TenantIdSessionId>UserId>. I componenti del filtro della query determinano se la query è una query a partizione singola, una query tra partizioni di destinazione o una query fan-out.

Query Definizione dei percorsi di trasferimento
SELECT * FROM c WHERE c.TenantId = 'Microsoft' AND c.UserId = '8411f20f-be3e-416a-a3e7-dcd5a3c1f28b' AND c.SessionId = '0000-11-0000-1111' Indirizzato alla singola partizione logica e fisica che contiene i dati per i valori specificati di TenantId, UserIde SessionId.
SELECT * FROM c WHERE c.TenantId = 'Microsoft' AND c.UserId = '8411f20f-be3e-416a-a3e7-dcd5a3c1f28b' Instradato solo al subset di destinazione di partizioni logiche e fisiche che contengono dati per i valori specificati di TenantId e UserId. Questa query è una query tra partizioni di destinazione che restituisce dati per un utente specifico nel tenant.
SELECT * FROM c WHERE c.TenantId = 'Microsoft' Instradato solo al subset di destinazione di partizioni logiche e fisiche che contengono dati per il valore specificato di TenantId. Questa query è una query tra partizioni di destinazione che restituisce i dati per tutti gli utenti in un tenant.
SELECT * FROM c WHERE c.UserId = '8411f20f-be3e-416a-a3e7-dcd5a3c1f28b' Instradato a tutte le partizioni fisiche, con conseguente esecuzione di una query tra partizioni tra fan-out.
SELECT * FROM c WHERE c.SessionId = '0000-11-0000-1111' Instradato a tutte le partizioni fisiche, con conseguente esecuzione di una query tra partizioni tra fan-out.

Query a partizione singola in un contenitore partizionato

Di seguito è riportato un esempio di esecuzione di una query che include tutti i livelli di sottopartizione, rendendo effettivamente la query una query a partizione singola.

// 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
    }
}

Query su più partizioni di destinazione in un contenitore partizionato

Di seguito è riportato un esempio di query che include un subset dei livelli di sottopartizione, rendendo effettivamente questa query una query a più partizioni di destinazione.

// 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
    }
}

Limitazioni e problemi noti

  • L'uso di contenitori che usano chiavi di partizione gerarchica è supportato solo in .NET v3 SDK, in Java v4 SDK e nella versione di anteprima di JavaScript SDK. È necessario usare un SDK supportato per creare nuovi contenitori con chiavi di partizione gerarchica e per eseguire operazioni CRUD o di query sui dati. Il supporto per altri SDK, incluso Python, non è attualmente disponibile.
  • Esistono limitazioni con vari connettori di Azure Cosmos DB, ad esempio con Azure Data Factory.
  • È possibile specificare chiavi di partizione gerarchica solo fino a tre livelli in profondità.
  • Le chiavi di partizione gerarchica possono essere attualmente abilitate solo nei nuovi contenitori. È necessario impostare i percorsi delle chiavi di partizione al momento della creazione del contenitore e non è possibile modificarli in un secondo momento. Per usare partizioni gerarchiche in contenitori esistenti, creare un nuovo contenitore con le chiavi di partizione gerarchiche impostate e spostare i dati usando i processi di copia del contenitore.
  • Le chiavi di partizione gerarchica sono attualmente supportate solo per gli account API per NoSQL. Le API per MongoDB e Cassandra non sono attualmente supportate.
  • Le chiavi di partizione gerarchica non sono attualmente supportate con la funzionalità Autorizzazioni. Non è possibile assegnare un'autorizzazione a un prefisso parziale del percorso della chiave di partizione gerarchica. Le autorizzazioni possono essere assegnate solo all'intero percorso della chiave di partizione logica. Ad esempio, se è stato partizionato da TenantId - >UserId, non è possibile assegnare un'autorizzazione per un valore specifico di TenantId. Tuttavia, è possibile assegnare un'autorizzazione per una chiave di partizione se si specifica sia il valore per TenantId che ''UserId'''.

Passaggi successivi