Para particionar ou não particionar?

8

Depois de ler várias perguntas sobre SO, postagens externas no blog e manual

Ainda me pergunto se devo ir com o particionamento considerando meu caso ou não.

O caso - simplificado

Armazenando dados do cliente. Todos os nomes das tabelas mencionadas abaixo são compensados.

  1. Tendo objetos que são identificáveis ​​pelo cliente e são seres não-físicos, também seus objetos físicos nos quais eles são realmente armazenados no caso de precisar enviar alguns objetos de volta ao cliente sob demanda ou processá-lo de outras maneiras. Eles são mapeados em um relacionamento muitos-para-muitos. objects_nonphysical, objects_physical, objects_mapping_table.

  2. O segundo relacionamento muitos para muitos é entre esses objetos não físicos e suas métricas. Existem objetos que estão vinculados a algumas métricas. metrics,metrics_objects_nonphysical

  3. Os objetos não-físicos e físicos têm suas tabelas de hierarquia que são relações pai-filho. objects_nonphysical_hierarchy,objects_physical_hierarchy

Dependendo das necessidades e requisitos de cada cliente, os dados sobre objetos físicos podem ser fornecidos ou necessários a partir do zero. Basicamente, o que eu preciso fazer é:

  • Mantenha o sistema interno para instruções INSERTe SELECTdeclarações rápidas , porque é aqui que o mapeamento será realizado.

  • Mantenha o sistema para o cliente externo visualizar e operar seus objetos não físicos - recuperação rápida de dados. Forte necessidade de eficiência nas SELECTdeclarações - esses dados estão disponíveis para muitos clientes pesquisarem quando quiserem.

Minha consideração

Pode haver um cliente, que pode acessar os dados, visualizá-los e operá-los, mas isso não precisa ser um contratado para o qual obtivemos os dados / estamos processando os dados.

Isso me levou a introduzir o particionamento de tabela no meu sistema, considerando que eu sempre sei em quais dados da partição se enquadram ( particionamento para contratados ) e, em seguida, cria o sistema para o cliente externo, onde eu preciso particionar para os clientes (isso seria feito com alguns atrasar o uso de ferramentas de automação e conjunto de regras para reescrever os dados da maneira dos clientes, para que, para cada cliente, verifiquemos apenas uma partição para cada tabela.

Volume de dados

Meus dados vão crescer constantemente, especialmente ao importar objetos e métricas de novos clientes. O ritmo de entrada de novos dados no sistema é imprevisível no momento a longo prazo. Realmente não há como medir isso sem saber quem será o próximo cliente. No momento, existem apenas 2 clientes com mais ou menos 1 milhão de linhas para cada cliente em todas as tabelas. Mas, no futuro, prevejo que novos clientes também venham com um volume de 10 milhões de linhas.

Questões

Essas questões estão todas relacionadas entre si.

  1. O particionamento deve realmente ser considerado aqui, ou isso é um exagero? Considero que é útil, pois estou sempre digitalizando exatamente uma partição.
  2. Se o particionamento é o caminho a seguir, como impor FKrestrições da maneira mais eficaz, considerando minhas necessidades? Devo procurar constraint triggers, ou apenas mantê-lo na camada de aplicação do sistema interno, ou talvez algum outro método?
  3. Se o particionamento não é o caminho a seguir, em que devo mergulhar?

Se não houver dados suficientes, informe-nos nos comentários abaixo.

Kamil Gosciminski
fonte
3
Em geral recomenda-se para iniciar a produção, sem qualquer sobrecarga de índices, divisórias, etc, em seguida, se os índices necessários add e divisórias etc.
alonk
11
Com o particionamento, você só obtém acelerações em determinados tipos de consultas e afeta outros tipos de consultas. Você também terá um impacto nas gravações. Particionar não deve ser a primeira coisa a ser alcançada, e acho que você poderá usar índices simples no futuro próximo e atravessar essas pontes quando chegar a elas. Linhas de 5 milhões não são tão grandes. Este pode ser um blog útil com comparações de velocidade: if-not-true-then-false.com/2009/…
dizzystar 4/16
2
Eu concordo com dizzystar, eu não me incomodaria agora. Atravesse a ponte se você a alcançar. Atualmente, o particionamento no Postgres também dificulta (se não é impossível) o uso de chaves estrangeiras apropriadas (isso pode mudar com 9.7, mas nada está resolvido ainda). Mesmo uma tabela com 50 milhões de linhas não é necessariamente uma candidata a particionamento. Se você tem principalmente condições de igualdade em suas consultas que reduzem o número de linhas substancialmente, boa indexação você pode obter um longo caminho.
a_horse_with_no_name
11
Para mim, não está muito claro o que você quer dizer com "particionamento para contratados". As tabelas que os contratados usam são diferentes das que pertencem a um cliente? Já aconteceu que o cliente A precisa acessar os dados do cliente B? Caso contrário, separar dados específicos do cliente em um esquema por cliente pode ser um caminho a percorrer - mas não necessariamente para o desempenho, mas para a separação de preocupações (maior segurança / privacidade e assim por diante).
dezso 30/03

Respostas:

1

Existem muitas questões em aberto na sua pergunta, mas o particionamento por cliente pode ser o caminho a seguir - especialmente se:

  • você espera muitos clientes,
  • cada um deles pode ter toneladas de dados ("toneladas" significa muito mais que o tamanho do cache de RAM),
  • a maioria de seus conjuntos de dados será mutuamente exclusiva (cada cliente vê diferentes subconjuntos de dados).

REGRAS ou gatilhos são uma sobrecarga de desempenho e podem ser evitados.

Considere algo nesse sentido:

BEGIN;

CREATE USER tenant1;
CREATE USER tenant2;

CREATE SCHEMA app;
CREATE SCHEMA tenant1;
CREATE SCHEMA tenant2;

CREATE TABLE app.objects_nonphysical(id int);
CREATE TABLE app.objects_physical(id int);
CREATE TABLE app.objects_mapping(id int);    
CREATE TABLE tenant1.objects_nonphysical() INHERITS(app.objects_nonphysical);
CREATE TABLE tenant1.objects_physical() INHERITS(app.objects_physical);
CREATE TABLE tenant1.objects_mapping() INHERITS(app.objects_mapping);
CREATE TABLE tenant2.objects_nonphysical() INHERITS(app.objects_nonphysical);
CREATE TABLE tenant2.objects_physical() INHERITS(app.objects_physical);
CREATE TABLE tenant2.objects_mapping() INHERITS(app.objects_mapping);

GRANT USAGE ON SCHEMA tenant1 TO tenant1;
GRANT USAGE ON SCHEMA tenant2 TO tenant2;
GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA tenant1 TO tenant1;
GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA tenant2 TO tenant2;

/* TEST: simulate login as customer */
SET SESSION AUTHORIZATION tenant2;
/* No schema needed - default search_path works */
SELECT count(*) FROM objects_nonphysical; 

ROLLBACK;

Você não precisa de nenhum gatilho / regra para mantê-lo.

Existem pontas abertas aqui - isso é apenas um rascunho ... Alguns problemas:

  • PK, FK e índices não são "herdados".
  • mesmo se você criá-los, o PK não será imposto na tabela mestre
  • você pode superar isso usando a mesma sequência para todos os inquilinos
  • obviamente, a aplicação deve ser ajustada para este modelo
filiprem
fonte
0

Não será prejudicial se você implementar o particionamento agora, mas use uma única partição até que o sistema realmente exija uma nova. Em termos de desempenho, haverá apenas uma pequena sobrecarga, para lidar com chaves primárias e coisas do gênero.

Eu recomendo o uso de regras para redirecionar inserções e uma tabela externa para as chaves primárias (por exemplo CREATE TABLE objects_physical_ids (id bigserial NOT NULL PRIMARY KEY), junto com um acionador de função que insere uma linha na tabela de ids e a copia para NEW.id (por exemplo INSERT INTO objects_physical_ids DEFAULT VALUES RETURNING id INTO NEW.id;), e outros acionadores que tratam da exclusão e atualizações, e um gatilho executando esses gatilhos de função para cada tabela herdada (não se esqueça de fazer isso ao criar uma nova tabela herdada!). Todas as tabelas relacionadas podem ter uma FOREIGN KEYna tabela de IDs relevantes (incluindo quaisquer ações de chave estrangeira, como ON UPDATEou ON DELETE)

Ziggy Crueltyfree Zeitgeister
fonte
2
As regras e gatilhos definitivamente têm sobrecarga e é fácil de medir. Além disso, eles adicionam complexidade e tornam a depuração (muito) mais difícil. Além disso, depois de seguir esse caminho várias vezes, eu sugeriria (sem reconhecer todos os detalhes) manter uma tabela pai vazia e uma ou mais partições filho. Ao alterar o esquema de particionamento, isso pode ser muito útil.
dezso 30/03