Partizionare o non partizionare?


8

Avendo già letto diverse domande su SO, post di blog esterni e manuali

Mi trovo ancora a chiedermi se dovrei andare con il partizionamento considerando il mio caso o meno.

Il caso - semplificato

Archiviazione dei dati dei clienti. Tutti i nomi delle tabelle menzionate di seguito sono fatti per chiarezza.

  1. Avere oggetti che sono identificabili dal cliente e sono esseri non fisici, anche i loro oggetti fisici in cui sono effettivamente archiviati nel caso in cui sia necessario rispedire alcuni oggetti al cliente su richiesta o elaborarli in altri modi. Sono mappati in una relazione molti-a-molti. objects_nonphysical, objects_physical, objects_mapping_table.

  2. La seconda relazione molti-a-molti è tra quegli oggetti non fisici e le loro metriche. Ci sono oggetti che sono legati con alcune metriche. metrics,metrics_objects_nonphysical

  3. Sia gli oggetti non fisici che quelli fisici hanno le loro tabelle gerarchiche che sono relazioni figlio-genitore. objects_nonphysical_hierarchy,objects_physical_hierarchy

A seconda delle esigenze e dei requisiti di ciascun cliente, i dati sugli oggetti fisici possono essere forniti o potrebbero essere creati da zero. Fondamentalmente, ciò che devo fare è:

  • Mantenere il sistema interno per veloce INSERTe SELECTdichiarazioni, perché qui è dove si svolgerà la mappatura.

  • Mantenere il sistema affinché i clienti esterni possano visualizzare e operare sui loro oggetti non fisici - recupero rapido dei dati. Forte necessità di efficienza per le SELECTdichiarazioni: questi dati sono disponibili per molti clienti per effettuare ricerche in qualsiasi momento.

La mia considerazione

Può esserci un cliente, che può accedere ai dati, visualizzarli e gestirli, ma non è necessario che sia un appaltatore per il quale abbiamo ottenuto i dati / per i quali li stiamo elaborando.

Questo mi ha portato a introdurre il partizionamento delle tabelle nel mio sistema, considerando che so sempre in quali dati di partizione dovrebbero rientrare (il partizionamento per gli appaltatori ) e quindi al sistema principale per i clienti esterni dove ho bisogno di partizionare per i clienti (questo sarebbe fatto con alcuni ritardare l'uso di strumenti di automazione e un insieme di regole per riscrivere i dati in modo clienti, in modo che per ogni cliente si esegua la scansione di una sola partizione per ogni tabella.

Volume di dati

I miei dati cresceranno costantemente, soprattutto durante l'importazione di oggetti e metriche di nuovi clienti. Il ritmo dei nuovi dati che arrivano nel sistema è imprevedibile al momento a lungo termine. Non c'è davvero modo di misurarlo non sapendo chi sarà il prossimo cliente. Al momento ci sono solo 2 clienti con più o meno 1 milione di righe per ogni cliente in ogni tabella. Ma in futuro prevedo che anche i nuovi clienti avranno un volume di circa 10 milioni di righe.

Domande

Queste domande sono tutte correlate tra loro.

  1. Il partizionamento dovrebbe davvero essere preso in considerazione qui o è eccessivo? Lo considero utile poiché eseguo sempre la scansione esattamente di una partizione.
  2. Se il partizionamento è la strada da percorrere, come posso applicare il FKvincolo nel modo più efficace considerando le mie esigenze? Dovrei andare per constraint triggers, o semplicemente tenerlo nel livello applicazione per il sistema interno, o forse qualche altro metodo?
  3. Se il partizionamento non è la strada da percorrere, in cosa dovrei tuffarmi?

Se non ci sono abbastanza dati forniti, per favore fatemi sapere nei commenti qui sotto.



3
In generale si consiglia di avviare la produzione senza sovraccarico di indici, partizioni ecc., Se necessario aggiungere indici e partizioni ecc.
solo dal

1
Con il partizionamento, si ottengono accelerazioni solo su determinati tipi di query mentre si ottiene un successo su altri tipi di query. Ti verrà anche un colpo sulle scritture. Il partizionamento non dovrebbe essere la prima cosa da raggiungere, e penso che starai bene usando indici semplici per il prossimo futuro e attraverserai quei ponti quando arriverai a loro. Le righe 5M non sono così grandi. Questo potrebbe essere un blog utile con confronti di velocità: if-not-true-then-false.com/2009/…
dizzystar

2
Sono d'accordo con Dizzystar, non mi preoccuperei proprio ora. Attraversa quel ponte se lo raggiungi. Attualmente il partizionamento in Postgres rende anche difficile (se non impossibile) usare le chiavi esterne appropriate (questo potrebbe cambiare con 9.7 ma nulla è ancora risolto). Anche una tabella con 50 milioni di righe non è necessariamente un candidato per il partizionamento. Se nelle query sono presenti principalmente condizioni di uguaglianza che riducono sostanzialmente il numero di righe, una buona indicizzazione può fare molto .
a_horse_with_no_name

1
Per me non è davvero chiaro cosa intendi per "partizionamento per gli appaltatori". Le tabelle utilizzate dagli appaltatori sono diverse da quelle che appartengono a un cliente? Accade mai che il cliente A debba accedere ai dati dal cliente B? In caso contrario, separare i dati specifici del cliente in uno schema per cliente potrebbe essere una strada da percorrere, ma non necessariamente per le prestazioni, ma per la separazione delle preoccupazioni (maggiore sicurezza / privacy e così via).
dezso,

Risposte:


1

Ci sono molte estremità aperte nella tua domanda, ma il partizionamento per cliente potrebbe essere la strada da percorrere, specialmente se:

  • ti aspetti molti clienti,
  • ognuno di essi potrebbe avere tonnellate di dati ("tonnellate" significa molto più della dimensione della cache RAM),
  • la maggior parte dei loro set di dati si escludono a vicenda (ogni cliente vede diversi sottogruppi di dati).

REGOLE o trigger sono un sovraccarico di prestazioni e possono essere evitati.

Considera qualcosa in questo senso:

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;

Non è necessario alcun trigger / regole per mantenerlo.

Ci sono delle estremità aperte qui - questa è solo una bozza ... Alcuni problemi:

  • PK, FK e indici non sono "ereditati".
  • anche se li crei, il PK non viene applicato sulla tabella principale
  • puoi superarlo usando la stessa sequenza per tutti gli inquilini
  • ovviamente, l'applicazione deve essere adattata per questo modello

0

Se non implementerai il partizionamento adesso, non ti farà male, ma usa una singola partizione fino a quando il tuo sistema non ne richiede davvero una nuova. Per quanto riguarda le prestazioni, ci sarà solo un piccolo overhead, per gestire le chiavi primarie e così via.

Consiglio di utilizzare le regole per il reindirizzamento degli inserti e una tabella esterna per le chiavi primarie (ad esempio CREATE TABLE objects_physical_ids (id bigserial NOT NULL PRIMARY KEY), insieme a un trigger di funzione che inserisce una riga nella tabella ID e la copia in NEW.id (ad esempio INSERT INTO objects_physical_ids DEFAULT VALUES RETURNING id INTO NEW.id;) e altri trigger che si occupano dell'eliminazione e gli aggiornamenti e un trigger che esegue quei trigger di funzione per ogni tabella ereditata (non dimenticare di farlo quando crei una nuova tabella ereditata!). Quindi tutte le tabelle correlate possono avere una FOREIGN KEYtabella id relativa (incluse eventuali azioni di chiave esterna come ON UPDATEo ON DELETE).


2
Le regole e i trigger hanno sicuramente un overhead ed è facile da misurare. Inoltre, aggiungono complessità e rendono il debugging (molto) più difficile. Inoltre, dopo essere andato giù più volte in questo modo, suggerirei (senza riconoscere tutti i dettagli) di mantenere una tabella padre vuota e una o più partizioni figlio. Quando si modifica lo schema di partizionamento, questo potrebbe tornare molto utile.
dezso
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.