2016-06-24 82 views
8

Io uso Ruby su binari supportati dal database oracle e memcached per il mio progetto corrente.Architettura di una funzione di scrittura intensiva

C'è una funzione piuttosto pesante utilizzata, che si basa su una singola vista del database come origine dati, e questa origine dati ha internamente altre viste e tabelle di database.

È una vista db virtuale, per poter accedere a tutto da un luogo, non a una vista db materializzata.

Gli utenti la maggior parte delle volte se sono nella funzione che stanno cercando di aggiornare, quindi avere dati aggiornati è importante.

Quando si ottengono dati da questa vista, I inner aggiunge la tabella di sicurezza alla vista (la tabella di sicurezza non fa parte della vista stessa) che contiene alcuni campi che usiamo per controllare l'accesso ai dati a un livello più granulare. Ad esempio, tabella di sicurezza ha colonne user_id, prop_1, prop_2, dove prop_1, prop_2 sono colonne disponibili in una vista db e user_id è un utente connesso. Alcuni utenti hanno gli stessi oggetti di scena nella tabella di sicurezza, diciamo prop_1 = 1 and prop_2 = 1, ma possono anche avere prop_1 come l'altro utente ma hanno diverso prop_1 = 2 and prop_2 = 1. Esistono molte combinazioni diverse di prop_1 e prop_2, pensandole come FK su un'altra tabella, quindi è possibile avere molte voci.

Ormai il tempo per recuperare i record sull'app è di circa 10 secondi, è piuttosto lento. Sto considerando un approccio alternativo.

La prima cosa che ho pensato era la vista materializzata, ma poiché l'utente fa frequenti aggiornamenti, potrebbe non essere la scelta migliore, poiché l'aggiornamento della vista potrebbe richiedere del tempo.

La seconda cosa che ho pensato è stata la cache, per utilizzare la combinazione prop_1 e prop_2 come chiave composta per i dati sottostanti, poiché molti utenti hanno la stessa combinazione e chiunque abbia la stessa combinazione può accedere agli stessi dati.

Tuttavia, questo approccio potrebbe richiedere più riscritture del codice e logica per salvare e recuperare i dati in frammenti, piuttosto da una posizione con una query come nella vista del database.

Nella tua esperienza, come hai risolto lo stesso problema? O c'è un approccio migliore che potrei provare?

Per quelli di voi che stanno per chiedere, cosa avete provato. Sto pensando prima alla soluzione, raccogliendo informazioni da risorse affidabili e persone più esperte, poi prenderò una decisione informata e inizierò ad attuare. L'implementazione prima, il secondo pensiero, si sono dimostrati così errati così tante volte

+1

tua domanda sembra implicare che l'adesione con la tabella di sicurezza è la ragione di un rallentamento delle prestazioni. Senza quella partecipazione, quanto tempo è necessario per recuperare record simili? –

risposta

0

Molte volte unirsi a una vista complessa presenta problemi di prestazioni.

Sono prop_1 e prop_2 valori a cui si desidera limitare? Cioè, stai unendo la tua vista alla tabella di sicurezza su quelle colonne, come

WHERE my_view.prop_1 = security_table.prop_1 
AND my_view.prop_2 = security_table.prop_2 
AND security_table.user_id = :current_user_id 

?

Domanda successiva: fare prop_1 e prop_2 mappare alle colonne nelle tabelle sottostanti della vista? In tal caso, possono essere utilizzati per accedere alle righe dalle tabelle sottostanti rapidamente (al di fuori della visualizzazione)?

Se è così, vorrei provare ad usare DBMS_RLS.ADD_POLICY aggiungere criteri di protezione sulle tabelle sottostanti per far rispettare la sicurezza (vale a dire, i valori limite di prop_1 e prop_2 in base all'utente corrente) e non si uniscono al tavolo di sicurezza per la vista a tutti.

Se si aggiungono le politiche di sicurezza alle tabelle sottostanti, Oracle aggiungerà tali predicati quando accedono alle tabelle, prima dello inizia la complessità della query. Ciò potrebbe dare all'ottimizzatore di Oracle l'ulteriore aiuto di cui ha bisogno per rendere il processo più veloce.

Senza vedere il tuo codice, è difficile dire di più.

1

È difficile dare una buona risposta senza ulteriori informazioni sulla visualizzazione, ma ci proverò.

Prima di tutto, interrogo l'uso di una singola vista molto complessa. Questo è difficile da regolare e può spesso causare problemi di prestazioni, quindi se è possibile suddividerlo nell'applicazione che sarebbe la mia prima scommessa.

In secondo luogo, hai esaminato il piano di esecuzione (spiega il piano) per la query con i filtri di sicurezza inclusi? Sta usando indici sensibili? In caso contrario, crearli. Forse le proprietà di sicurezza non sono indicizzate, per esempio?

Una terza opzione potrebbe essere quella di utilizzare PL/SQL e chiamare una stored procedure che funzioni come la vista. Questo ti dà più controllo nel database, rendendo possibile controllare la query e dividerla in più passaggi, ma per ottenere lo stesso risultato di Oggi.

Infine è possibile riscrivere la vista per prestazioni migliori. Una caratteristica spesso trascurata è la clausola WITH, che rende possibile eseguire una query prima della query principale e utilizzare il risultato come tabella. Mi ha aiutato a migliorare notevolmente le prestazioni di viste complesse.

DBMS_RLS è bello ma può essere costoso, richiede l'Enterprise Edition e non mi sorprende se è necessaria anche una licenza separata. Per prima cosa, opterei per una soluzione programmatica.

0

"si basa su una singola vista del database come origine dati e questa origine dati internamente ha altre viste e tabelle di database all'interno."

Se questo fosse un oggetto, lo chiameremmo a God Object, che è una cosa negativa. È tanto un anti-modello nel regno dei database. Senza conoscere i dettagli è difficile esserne certi, ma probabilmente hai un casino di inner join, outer join e cross joins, che portano alla de-normalizzazione, alla duplicazione dei dati e (forse) ai problemi di integrità.

Certamente si verificano problemi di prestazioni, il che è inevitabile perché una cosa del genere non è sintonizzabile. Se vuoi una riga o diecimila righe è la stessa query. Non stai dando all'ottimizzatore la possibilità di prendere decisioni sensate.

Quindi la prima cosa che devi fare è suddividere questa vista in oggetti dati significativi (viste o tabelle) che mappano a domini aziendali focalizzati. Stai già utilizzando Rails, non dovrebbe essere così difficile gestire un Data Access Layer migliore.

Per quanto riguarda la sicurezza, Oracle dispone di un'implementazione di Virtual Private Database integrata. Se si dispone di Enterprise Edition, è necessario utilizzare DBMS_RLS per controllare l'accesso a livello di riga (e livello di colonna).Il vantaggio principale di RLS è che è invisibile: imposta un criterio su una tabella o una vista e viene applicato automaticamente a tutto l'SQL eseguito sull'oggetto.

Se si è su Standard Edition, si è bloccati con l'utilizzo di join espliciti sulla tabella di sicurezza (ma vedere di seguito).

Come per l'uso di memcached, nella mia esperienza gli sviluppatori di applicazioni tendono a costruire cache esterne perché non capiscono come funzionano i database Oracle e quindi implementano strategie di accesso ai dati scarse - come il routing di tutto attraverso una singola vista mostruosa.

Rompere il DAL in oggetti significativi e significativi ti offrirà prestazioni migliori perché l'ottimizzatore del database sarà in grado di selezionare il percorso più efficiente per estrarre l'insieme preciso di informazioni necessarie. Anche i percorsi di recupero saranno migliori perché i blocchi hot (più frequentemente interrogati) saranno di aiuto nella cache del buffer del database, mentre al momento sospetto che venga completamente distrutto da un eccesso di scansioni complete della tabella. È possibile sfruttare il caching dei risultati del server, che potrebbe aiutare con "gli utenti hanno la stessa combinazione e [chi] può accedere agli stessi dati" Find out more.

Quindi potresti trovare che non hai bisogno di un cache esterna. Certamente facendo in modo che il database gestisca correttamente i suoi dati, utilizzando la tecnologia in modo appropriato, dovresti scoprire che hai bisogno di molti meno dati esternamente. Descrivi la tua applicazione come "write intensive", quindi devi passare molti cicli mantenendo sincronizzati la cache e il database. Ovviamente, se hai a che fare con quantità di dati di Facebook, devi utilizzare gli approcci in stile Facebook per la gestione dei dati. Ma generalmente, Do The Simplest Thing That Could Possibly Work rimane il miglior punto di partenza.

1

Se si subiscono alcune latenze probabilmente causate dal db, è possibile migrare alcune delle proprie viste a un REDIS database (archivio di strutture dati in memoria) che è probabilmente uno dei più efficienti in "lettura/scrittura" intensivo.

Per quanto riguarda l'aggiornamento problematico, è possibile implementare un websocket per diffondere/inviare l'aggiornamento preciso direttamente a chi ne ha bisogno.

Sottolineo che questa possibilità ha richiesto alcune modifiche su entrambi i lati del server del client &, ma presumo che sia l'approccio migliore per mantenere aggiornata la vista dell'utente finale con bassa latenza.

migliori saluti