2015-11-20 33 views
8

Im la creazione di un back-end e-commerce dove in ogni mio prodotto ha i seguenti attributi contatoreImplementazione calibro, commentare, vista contatore per un prodotto

- product views 
- product likes 
- product comments count 

le colonne del database corrente che ho per la tabella del database del prodotto è

- id 
- likes_count 
- views_count 
- comments_count 
- category_id 
- category_parent_id 
- category_sub_parent_id 
- handling_charge 
- shipping_charge 
- meetup_address 
- is_additional_fields 
- status 
- is_deleted 
- created_at 
- updated_at 

Come si vede nella seguente blog Wanelo engineering blog implementare un contatore che possono spesso aggiornarsi una singola fila causerebbe blocco di riga su cui innodb se ottenere aggiornato frequentemente può causare situazioni dead lock in th e applicazione. Ma la soluzione per questo è praticamente spiegata nel blog di cui ho avuto un'idea. Ma cosa succede se ci sono più contatori associati a un singolo prodotto che possono essere aggiornati simultaneamente quando l'app cresce. Come dovrei progettare la tabella del database per i contatori. Devo devono mantenere tabelle separate cioè

likes counter table 

- id  - product_id  - count 

views counter table 

- id  - product_id  - count 

comments counter table 

- id  - product_id  - count 

Mantenendo tabella separata anche se un aggiornamento simultaneo viene per un prodotto (come + testa + vista) sarà aggiornato separatamente e riduce la possibilità di situazioni dead lock riga. Se è in una singola tabella e se gli aggiornamenti per tutti vengono contemporaneamente possono causare un problema.

Domanda: C'è un modo migliore in cui è possibile progettare i tavoli per un contatore? Qualche suggerimento per favore?

+0

considerazione facendo tutti gli inserti invece di incrementare un valore. in questo modo è possibile segnalare (contare) quando si è verificato tale traffico. o forse raggruppare un valore incrementale per giorno/mese/ecc. – binnyb

risposta

2

Un contatore nella tabella prodotti per le viste va bene.

Una tabella separata per i Mi piace con colonne come (product_id, user_id) in modo che a ciascun utente possa piacere un prodotto solo una volta. Altrimenti sarebbero in grado di schiacciare come se fosse solo un semplice contatore.

Una tabella separata per i commenti con le colonne, come (product_id, comment_text, data .. ecc)

E 'questo quello che stai chiedendo?

+0

Grazie per la risposta. Abbiamo tabelle diverse in cui i commenti e i mi piace sono mappati all'utente. La tabella dei contatori registra solo il conteggio del numero di commenti o viste. Ma i conteggi dovrebbero essere mantenuti separatamente?Come può causare problemi durante gli aggiornamenti quando aumenta il numero di colpi. – Ajeesh

+1

Immagino che diffondere il più possibile blocchi di file il più possibile non guasta. Un po 'più fastidioso quando si scrive codice. Forse potresti simulare il traffico elevato/la quantità elevata di situazioni di input dell'utente e controllare i log per vedere le informazioni di deadlock. Questo potrebbe aiutarti a determinare se ne vale la pena. Scrivi alcuni cicli che aggiornano i contatori e dormono per millisecondi casuali 1-100 tra gli aggiornamenti del contatore e li eseguono per alcune ore. –

+0

Per curiosità, hai eseguito delle simulazioni? E quali sono stati i risultati? –

0

L'uso di code di sfondo per il buffering di inserti/aggiornamenti come suggerito nel collegamento condiviso è piuttosto standard e stavo per suggerire lo stesso.

È possibile ricalcolare più contatori allo stesso modo di un contatore singolo. I conteggi delle viste possono essere memorizzati nella cache in Memcached/Redis, oppure è possibile memorizzarli in una tabella separata (anche se suggerirei di utilizzare solo una soluzione di analisi per questo).

Nel vostro lavoratore:

class ProductCountsWorker 
    # ... 

    def perform(product_id) 
    Product.find(product_id).update_counts! 
    end 
end 

E nel modello:

class Product < ActiveRecord::Base 
    # ... 

    after_create :init_views_count_buffer 

    private 

    def init_views_count_buffer 
    reset_views_count_buffer(views_count || 0) 
    end 

    def views_count_cache_key 
    "#{cache_key}/views_count_buffer" 
    end 

    def reset_views_count_buffer(value = 0) 
    Rails.cache.set(views_count_cache_key, value) 
    end 

    # Called from controllers etc 
    def increment_views_count_buffer 
    Rails.cache.increment(views_count_cache_key) 
    end 

    def update_counts! 
    transaction do 
     update!(
     likes_count: likes.count, 
     views_count: views_count + (Rails.cache.fetch(views_count_cache_key) || 0), 
     # Or, if you have a separate views table: 
     # views_count: views.count, 
     comments_count: comments.count, 
    ) 
     reset_views_count_buffer 
    end 
    end 
end 

Un altro suggerimento sarebbe divideremo questa funzionalità conteggio delle visualizzazioni a una preoccupazione.

Rails Low-Level Caching docs