Alcune aggiunte a una determinata serie di risposte:
Prima di tutto, se hai intenzione di utilizzare l'hash Redis in modo efficiente, devi conoscere le chiavi che contano il numero massimo e i valori della dimensione massima, altrimenti se scompaiono hash-max-ziplist-value o hash-max-ziplist-entry, Redis lo convertirà in praticamente solite coppie chiave / valore sotto un cofano. (vedi hash-max-ziplist-value, hash-max-ziplist-entry) E rompere sotto una cappa dalle opzioni di hash È DAVVERO MALE, perché ogni normale coppia chiave / valore all'interno di Redis utilizza +90 byte per coppia.
Significa che se inizi con l'opzione due e rompi accidentalmente il valore max-hash-ziplist-otterrai +90 byte per OGNI ATTRIBUTO che hai all'interno del modello utente! (in realtà non il +90 ma +70 vedi l'output della console di seguito)
# you need me-redis and awesome-print gems to run exact code
redis = Redis.include(MeRedis).configure( hash_max_ziplist_value: 64, hash_max_ziplist_entries: 512 ).new
=> #<Redis client v4.0.1 for redis://127.0.0.1:6379/0>
> redis.flushdb
=> "OK"
> ap redis.info(:memory)
{
"used_memory" => "529512",
**"used_memory_human" => "517.10K"**,
....
}
=> nil
# me_set( 't:i' ... ) same as hset( 't:i/512', i % 512 ... )
# txt is some english fictionary book around 56K length,
# so we just take some random 63-symbols string from it
> redis.pipelined{ 10000.times{ |i| redis.me_set( "t:#{i}", txt[rand(50000), 63] ) } }; :done
=> :done
> ap redis.info(:memory)
{
"used_memory" => "1251944",
**"used_memory_human" => "1.19M"**, # ~ 72b per key/value
.....
}
> redis.flushdb
=> "OK"
# setting **only one value** +1 byte per hash of 512 values equal to set them all +1 byte
> redis.pipelined{ 10000.times{ |i| redis.me_set( "t:#{i}", txt[rand(50000), i % 512 == 0 ? 65 : 63] ) } }; :done
> ap redis.info(:memory)
{
"used_memory" => "1876064",
"used_memory_human" => "1.79M", # ~ 134 bytes per pair
....
}
redis.pipelined{ 10000.times{ |i| redis.set( "t:#{i}", txt[rand(50000), 65] ) } };
ap redis.info(:memory)
{
"used_memory" => "2262312",
"used_memory_human" => "2.16M", #~155 byte per pair i.e. +90 bytes
....
}
Per la risposta di TheHippo, i commenti sull'opzione 1 sono fuorvianti:
hgetall / hmset / hmget in soccorso se sono necessari tutti i campi o più operazioni get / set.
Per la risposta BMiner.
La terza opzione è davvero divertente, per il set di dati con max (id) <ha-max-ziplist-value questa soluzione ha una complessità O (N), perché, sorpresa, Reddis memorizza piccoli hash come contenitore array-like di lunghezza / chiave / valore oggetti!
Ma molte volte gli hash contengono solo pochi campi. Quando gli hash sono piccoli, invece, possiamo semplicemente codificarli in una struttura di dati O (N), come un array lineare con coppie di valori chiave con prefisso di lunghezza. Dato che lo facciamo solo quando N è piccolo, il tempo ammortizzato per i comandi HGET e HSET è ancora O (1): l'hash verrà convertito in una vera tabella hash non appena il numero di elementi che contiene aumenterà troppo
Ma non dovresti preoccuparti, romperai le voci hash-max-ziplist molto velocemente e qui andrai ora alla soluzione numero 1.
Molto probabilmente la seconda opzione passerà alla quarta soluzione sotto copertura, come afferma la domanda:
Tieni presente che se uso un hash, la lunghezza del valore non è prevedibile. Non sono tutti brevi come l'esempio bio sopra.
E come hai già detto: la quarta soluzione è sicuramente il +70 byte più costoso per ogni attributo.
Il mio suggerimento su come ottimizzare tale set di dati:
Hai due opzioni:
Se non è possibile garantire la dimensione massima di alcuni attributi utente di quanto si vada per la prima soluzione e se la materia di memoria è fondamentale rispetto a comprimere json utente prima di archiviare in redis.
Se riesci a forzare la dimensione massima di tutti gli attributi. Puoi quindi impostare hash-max-ziplist-entry / value e utilizzare gli hash come hash per rappresentazione dell'utente o come ottimizzazione della memoria hash da questo argomento di una guida Redis: https://redis.io/topics/memory-optimization e memorizza l'utente come stringa json. In entrambi i casi è anche possibile comprimere attributi utente lunghi.