Design das consultas
As soluções de serviço de tabela podem ser intensivas de leitura, escrita intensiva ou uma mistura dos dois. Este artigo foca-se nos aspetos a ter em conta quando estiver a conceber o serviço Tabela para suportar operações de leitura de forma eficiente. Normalmente, um design que suporte operações de leitura de forma eficiente também é eficiente para operações de escrita. No entanto, existem considerações adicionais a ter em conta ao conceber para suportar operações de escrita, abordadas no artigo Estrutura para modificação de dados.
Um bom ponto de partida para conceber a sua solução de serviço Tabela para lhe permitir ler dados de forma eficiente é perguntar "Que consultas a minha aplicação terá de executar para obter os dados de que precisa a partir do serviço Tabela?"
Nota
Com o serviço Tabela, é importante que a estrutura seja correta antecipadamente, porque é difícil e dispendioso alterá-la mais tarde. Por exemplo, numa base de dados relacional, muitas vezes é possível resolver problemas de desempenho simplesmente ao adicionar índices a uma base de dados existente: esta não é uma opção com o serviço Tabela.
Esta secção foca-se nos principais problemas que tem de resolver quando estrutura as tabelas para consulta. Os tópicos abordados nesta secção incluem:
- Como a sua escolha de PartitionKey e RowKey afeta o desempenho das consultas
- Escolher uma Chave de Partição adequada
- Otimizar consultas para o serviço Tabela
- Ordenar dados no serviço Tabela
Como a sua escolha de PartitionKey e RowKey afeta o desempenho das consultas
Os exemplos seguintes pressupõem que o serviço de tabela está a armazenar entidades de colaboradores com a seguinte estrutura (a maioria dos exemplos omitem a propriedade Carimbo de Data/Hora para maior clareza):
Nome da coluna | Tipo de dados |
---|---|
PartitionKey (Nome do Departamento) | String |
RowKey (ID do Funcionário) | String |
FirstName | String |
LastName | String |
Age | Número inteiro |
EmailAddress | String |
O artigo Descrição geral do armazenamento de Tabelas do Azure descreve algumas das principais funcionalidades do serviço tabela do Azure que têm uma influência direta na conceção da consulta. Estes resultam nas seguintes diretrizes gerais para conceber consultas do serviço Tabela. Tenha em atenção que a sintaxe de filtro utilizada nos exemplos abaixo é da API REST do serviço Tabela, para obter mais informações, consulte Entidades de Consulta.
- Uma Consulta de Ponto é a pesquisa mais eficiente a utilizar e recomenda-se que seja utilizada para pesquisas de volume elevado ou pesquisas que exijam a latência mais baixa. Esta consulta pode utilizar os índices para localizar uma entidade individual de forma muito eficiente ao especificar os valores PartitionKey e RowKey . Por exemplo: $filter=(PartitionKey eq 'Sales') e (RowKey eq '2')
- A segunda melhor é uma Consulta de Intervalo que utiliza PartitionKey e filtra um intervalo de valores RowKey para devolver mais do que uma entidade. O valor PartitionKey identifica uma partição específica e os valores RowKey identificam um subconjunto das entidades nessa partição. Por exemplo: $filter=PartitionKey eq "Sales" e RowKey ge 'S' e RowKey lt 'T'
- A terceira melhor é uma Análise de Partições que utiliza PartitionKey e filtra noutra propriedade não chave e que pode devolver mais do que uma entidade. O valor PartitionKey identifica uma partição específica e os valores de propriedade selecionam para um subconjunto das entidades nessa partição. Por exemplo: $filter=PartitionKey eq "Sales" e LastName eq "Smith"
- Uma Análise de Tabelas não inclui a PartitionKey e é muito ineficaz porque procura todas as partições que compõem a sua tabela por sua vez para quaisquer entidades correspondentes. Efetuará uma análise de tabela, independentemente de o filtro utilizar ou não o RowKey. Por exemplo: $filter=LastName eq 'Jones'
- As consultas que devolvem múltiplas entidades devolvem-nas ordenadas pela ordem PartitionKey e RowKey . Para evitar recorrer às entidades no cliente, escolha uma RowKey que defina a sequência de ordenação mais comum.
Tenha em atenção que a utilização de um "ou" para especificar um filtro com base nos valores RowKey resulta numa análise de partição e não é tratada como uma consulta de intervalo. Por conseguinte, deve evitar consultas que utilizem filtros como: $filter=PartitionKey eq "Sales" e (RowKey eq '121' ou RowKey eq '322')
Para obter exemplos de código do lado do cliente que utilizam a Biblioteca de Cliente de Armazenamento para executar consultas eficientes, veja:
- Executar uma consulta de ponto com a Biblioteca de Cliente de Armazenamento
- Obter várias entidades com LINQ
- Projeção do lado do servidor
Para obter exemplos de código do lado do cliente que podem processar vários tipos de entidade armazenados na mesma tabela, veja:
Escolher uma Chave de Partição adequada
A sua escolha de PartitionKey deve equilibrar a necessidade de permitir a utilização de transações de grupos de entidades (para garantir a consistência) em relação ao requisito de distribuição das entidades por várias partições (para garantir uma solução dimensionável).
Num extremo, pode armazenar todas as entidades numa única partição, mas isto pode limitar a escalabilidade da sua solução e impedir que o serviço de tabela consiga fazer o balanceamento de carga dos pedidos. No outro extremo, pode armazenar uma entidade por partição, que seria altamente dimensionável e que permite ao serviço de tabela fazer o balanceamento de carga de pedidos, mas que o impediria de utilizar transações de grupo de entidades.
Uma PartitionKey ideal é aquela que lhe permite utilizar consultas eficientes e que tem partições suficientes para garantir que a sua solução é dimensionável. Normalmente, verá que as suas entidades terão uma propriedade adequada que distribui as suas entidades por partições suficientes.
Nota
Por exemplo, num sistema que armazena informações sobre utilizadores ou funcionários, o UserID pode ser uma boa PartitionKey. Pode ter várias entidades que utilizam um determinado UserID como chave de partição. Cada entidade que armazena dados sobre um utilizador é agrupada numa única partição, pelo que estas entidades são acessíveis através de transações de grupo de entidades, sendo ainda altamente dimensionáveis.
Existem considerações adicionais na sua escolha de PartitionKey relacionadas com a forma como irá inserir, atualizar e eliminar entidades. Para obter mais informações, veja Estruturar tabelas para modificação de dados.
Otimizar consultas para o serviço Tabela
O serviço Tabela indexa automaticamente as suas entidades através dos valores PartitionKey e RowKey num único índice agrupado, daí que as consultas de ponto sejam as mais eficientes a utilizar. No entanto, não existem outros índices que não sejam os do índice agrupado nas PartitionKey e RowKey.
Muitos designs têm de cumprir os requisitos para ativar a pesquisa de entidades com base em múltiplos critérios. Por exemplo, localizar entidades de colaboradores com base no e-mail, no ID do funcionário ou no apelido. Os padrões descritos em Padrões de Estrutura de Tabelas abordam estes tipos de requisitos e descrevem formas de contornar o facto de o serviço Tabela não fornecer índices secundários:
- Padrão de índice secundário de intra partição – armazene várias cópias de cada entidade com valores RowKey diferentes (na mesma partição) para ativar pesquisas rápidas e eficientes e sequências de ordenação alternativas com valores RowKey diferentes.
- Padrão de índice secundário entre partições – armazene várias cópias de cada entidade através de diferentes valores RowKey em partições separadas ou em tabelas separadas para permitir pesquisas rápidas e eficientes e sequências de ordenação alternativas através de diferentes valores RowKey .
- Padrão de Entidades de Índice – mantenha as entidades de índice para permitir pesquisas eficientes que devolvem listas de entidades.
Ordenar dados no serviço Tabela
O serviço Tabela devolve entidades ordenadas por ordem ascendente com base em PartitionKey e, em seguida , por RowKey. Estas chaves são valores de cadeia e, para garantir que os valores numéricos são ordenados corretamente, deve convertê-los num comprimento fixo e acolhê-los com zeros. Por exemplo, se o valor do ID do funcionário que utiliza como RowKey for um valor inteiro, deverá converter o ID do funcionário 123 em 00000123.
Muitas aplicações têm requisitos para utilizar dados ordenados em encomendas diferentes: por exemplo, ordenar funcionários por nome ou por data de adesão. Os padrões seguintes abordam como alternar encomendas de ordenação para as suas entidades:
- Padrão de índice secundário de intra partição – armazene várias cópias de cada entidade com valores RowKey diferentes (na mesma partição) para ativar pesquisas rápidas e eficientes e sequências de ordenação alternativas com valores RowKey diferentes.
- Padrão de índice secundário entre partições – armazene múltiplas cópias de cada entidade utilizando diferentes valores RowKey em partições separadas em tabelas separadas para permitir pesquisas rápidas e eficientes e sequências de ordenação alternativas através de diferentes valores RowKey.
- Padrão de cauda de registo – obtenha as entidades n adicionadas mais recentemente a uma partição com um valor RowKey que ordena por ordem de data e hora inversa.