Escolher colunas de distribuição no Banco de Dados do Azure para PostgreSQL – Hiperescala (Citus)

Escolher a coluna de distribuição de cada tabela é uma das decisões de modelagem mais importantes que você tomará. O Banco de Dados do Azure para PostgreSQL – Hiperescala (Citus) armazena linhas em fragmentos com base no valor da coluna de distribuição das linhas.

A opção correta agrupa os dados relacionados nos mesmos nós físicos, o que torna as consultas rápidas e adiciona suporte a todos os recursos do SQL. Uma opção incorreta faz com que o sistema seja executado lentamente e não dará suporte a todos os recursos do SQL entre os nós.

Este artigo fornece dicas de colunas de distribuição para os dois cenários mais comuns da Hiperescala (Citus).

Aplicativos multilocatário

A arquitetura de multilocatário usa uma forma de modelagem de banco de dados hierárquica para distribuir consultas entre os nós do grupo de servidores. O início da hierarquia de dados é conhecida como a ID do locatário e precisa ser armazenada em uma coluna de cada tabela.

A Hiperescala (Citus) inspeciona consultas para ver qual ID de locatário elas envolvem e localiza o fragmento de tabela correspondente. Ela roteia a consulta para um nó de trabalho individual que contém o fragmento. A execução de uma consulta com todos os dados relevantes colocados no mesmo nó é chamada de colocação.

O diagrama a seguir ilustra a colocação no modelo de dados multilocatário. Ele contém duas tabelas, Contas e Campanhas, cada uma distribuída pela account_id. As caixas sombreadas representam fragmentos. Os fragmentos verdes são armazenados juntos em um nó de trabalho, e os fragmentos azuis são armazenados em outro nó de trabalho. Observe como uma consulta de junção entre Contas e Campanhas tem todos os dados necessários juntos em um nó quando as duas tabelas são restritas à mesma account_id.

Colocação multilocatário

Para aplicar esse design a um esquema próprio, identifique o que constitui um locatário no seu aplicativo. As instâncias comuns incluem empresa, conta, organização ou cliente. O nome da coluna será semelhante a company_id ou customer_id. Examine cada uma das consultas e faça esta pergunta: isso funcionará se ela tiver cláusulas WHERE adicionais para restringir todas as tabelas envolvidas às linhas com a mesma ID de locatário? As consultas no modelo de multilocatário estão no escopo de um locatário. Por exemplo, as consultas sobre as vendas ou o inventário estão no escopo de uma loja específica.

Práticas recomendadas

  • Particione tabelas distribuídas por uma coluna tenant_id comum. Por exemplo, em um aplicativo SaaS em que os locatários são empresas, provavelmente, a tenant_id será a company_id.
  • Converta pequenas tabelas entre locatários em tabelas de referência. Quando vários locatários compartilharem uma pequena tabela de informações, distribua-a como uma tabela de referência.
  • Restrinja e filtre todas as consultas de aplicativo por tenant_id. Cada consulta deve solicitar informações para um locatário por vez.

Leia o tutorial sobre multilocatário para obter um exemplo de como criar esse tipo de aplicativo.

Aplicativos em tempo real

A arquitetura de multilocatário apresenta uma estrutura hierárquica e usa a colocação de dados para rotear consultas por locatário. Por outro lado, as arquiteturas em tempo real dependem de propriedades de distribuição específicas dos dados para obter um processamento altamente paralelo.

Usamos a "ID da entidade" como um termo para colunas de distribuição no modelo em tempo real. As entidades típicas são usuários, hosts ou dispositivos.

As consultas em tempo real normalmente solicitam agregações numéricas agrupadas por data ou categoria. A Hiperescala (Citus) envia essas consultas a cada fragmento para resultados parciais e monta a resposta final no nó coordenador. As consultas são executadas mais rapidamente quando muitos nós contribuem o máximo possível e quando nenhum nó precisa realizar uma quantidade desproporcional de trabalho.

Práticas recomendadas

  • Escolha uma coluna com alta cardinalidade como a coluna de distribuição. Para comparação, um campo Status em uma tabela de pedidos com os valores Novo, Pago e Enviado é uma opção inadequada de coluna de distribuição. Ele pressupõe apenas esses poucos valores, o que limita o número de fragmentos que podem conter os dados e o número de nós que podem processá-lo. Entre as colunas com alta cardinalidade, também é bom escolher as colunas que são usadas com frequência em cláusulas group-by ou como chaves de junção.
  • Escolha uma coluna com distribuição uniforme. Se você distribuir uma tabela em uma coluna distorcida para determinados valores comuns, os dados da tabela tenderão a ser acumulados em alguns fragmentos. Os nós que mantêm esses fragmentos acabam realizando mais trabalho do que os outros nós.
  • Distribua tabelas de fatos e dimensões nas colunas comuns. A tabela de fatos só pode ter uma chave de distribuição. As tabelas unidas em outra chave não serão colocalizadas com a tabela de fatos. Escolha uma dimensão a ser colocalizada com base na frequência na qual ela é unida e no tamanho das linhas de junção.
  • Altere algumas tabelas de dimensões para tabelas de referência. Se uma tabela de dimensões não puder ser colocalizada com a tabela de fatos, aprimore o desempenho da consulta distribuindo cópias da tabela de dimensões para todos os nós na forma de uma tabela de referência.

Leia o tutorial sobre o painel em tempo real para obter um exemplo de como criar esse tipo de aplicativo.

Dados de série temporal

Em uma carga de trabalho de série temporal, os aplicativos consultam informações recentes enquanto arquivam informações antigas.

O erro mais comum em modelar informações de série temporal na Hiperescala (Citus) é usar o próprio carimbo de data/hora como uma coluna de distribuição. Uma distribuição de hash com base no tempo distribui os tempos de modo aleatória em fragmentos diferentes, em vez de manter os intervalos de tempo juntos em fragmentos. As consultas que envolvem tempo geralmente referenciam intervalos de tempo, por exemplo, os dados mais recentes. Esse tipo de distribuição de hash leva à sobrecarga da rede.

Práticas recomendadas

  • Não escolha um carimbo de data/hora como a coluna de distribuição. Escolha outra coluna de distribuição. Em um aplicativo multilocatário, use a ID do locatário, ou em um aplicativo em tempo real, use a ID da entidade.
  • Em vez disso, use o particionamento de tabela do PostgreSQL para a hora. Use o particionamento de tabela para dividir uma tabela grande de dados ordenados por hora em várias tabelas herdadas com cada tabela que contém intervalos de tempo diferentes. A distribuição de uma tabela particionada do Postgres na Hiperescala (Citus) cria fragmentos para as tabelas herdadas.

Próximas etapas

  • Saiba como a colocação entre os dados distribuídos ajuda as consultas a serem executadas rapidamente.