Quelques compléments à un ensemble donné de réponses :
Tout d'abord, si vous voulez utiliser efficacement le hachage Redis, vous devez savoir que a le nombre maximal de clés et la taille maximale des valeurs - sinon, s'ils dépassent hash-max-ziplist-value ou hash-max-ziplist-entries, Redis les convertira en paires clé/valeur pratiquement habituelles sous un capot. ( voir hash-max-ziplist-value, hash-max-ziplist-entries ) Et la rupture sous un capot à partir d'une option de hachage EST TRÈS MAUVAISE, parce que chaque paire clé/valeur habituelle dans Redis utilise +90 bytes par paire.
Cela signifie que si vous commencez avec l'option deux et que vous sortez accidentellement de la valeur max-hash-ziplist, vous obtiendrez +90 octets pour CHAQUE ATTRIBUTE que vous avez dans le modèle utilisateur ! ( en fait pas +90 mais +70 voir la sortie console ci-dessous )
# 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
....
}
Pour la réponse de TheHippo, les commentaires sur la première option sont trompeurs :
hgetall/hmset/hmget à la rescousse si vous avez besoin de tous les champs ou de plusieurs opérations get/set.
Pour la réponse de BMiner.
La troisième option est en fait très amusante, pour les ensembles de données avec max(id) < has-max-ziplist-value cette solution a une complexité O(N), parce que, surprise, Reddis stocke les petits hashs comme un conteneur de type tableau d'objets longueur/clé/valeur !
Mais souvent, les hachages ne contiennent que quelques champs. Lorsque les hachages sont petits, nous pouvons simplement les encoder dans une structure de données O(N), comme un tableau linéaire avec des paires clé-valeur préfixées par la longueur. Puisque nous ne faisons cela que lorsque N est petit, le temps amorti pour les commandes HGET et HSET est toujours O(1) : le hachage sera converti en une véritable table de hachage dès que le nombre d'éléments qu'il contient augmentera trop.
Mais ne vous inquiétez pas, vous casserez hash-max-ziplist-entries très rapidement et voilà, vous êtes maintenant à la solution numéro 1.
La deuxième option sera très probablement la quatrième solution sous un capot car comme le dit la question :
Gardez à l'esprit que si j'utilise un hachage, la longueur de la valeur n'est pas prévisible. Elles ne sont pas toutes courtes comme dans l'exemple de la bio ci-dessus.
Et comme vous l'avez déjà dit : la quatrième solution est la plus chère +70 octets pour chaque attribut, c'est certain.
Ma suggestion : comment optimiser un tel ensemble de données ?
Vous avez deux options :
-
Si vous ne pouvez pas garantir la taille maximale de certains attributs de l'utilisateur, alors vous optez pour la première solution, et si la question de la mémoire est cruciale, alors compressez le json de l'utilisateur avant de le stocker dans redis.
-
Si vous pouvez forcer la taille maximale de tous les attributs. Alors vous pouvez définir hash-max-ziplist-entries/value et utiliser les hashs soit comme un hash par représentation de l'utilisateur OU comme optimisation de la mémoire des hashs à partir de ce sujet d'un guide Redis : https://redis.io/topics/memory-optimization et stocker l'utilisateur sous forme de chaîne json. Dans les deux cas, vous pouvez également compresser les attributs longs de l'utilisateur.
44 votes
Gardez également à l'esprit que vous ne pouvez pas (facilement) stocker un objet JSON imbriqué dans un ensemble de hachage.
4 votes
ReJSON peut également vous aider dans ce domaine : redislabs.com/blog/redis-as-a-json-store