Einige Ergänzungen zu einer Reihe von Antworten:
Wenn Sie Redis-Hash effizient nutzen möchten, müssen Sie zunächst die maximale Anzahl der Schlüssel und die maximale Größe der Schlüssel kennen. Andernfalls konvertiert Redis den Hash-Max-Ziplist-Wert oder die Hash-Max-Ziplist-Einträge praktisch in übliche Schlüssel / Wert-Paare unter einer Haube. (siehe Hash-Max-Ziplist-Wert, Hash-Max-Ziplist-Einträge) Und das Unterbrechen einer Hash-Option unter einer Haube ist WIRKLICH SCHLECHT, da jedes übliche Schlüssel / Wert-Paar in Redis +90 Bytes pro Paar verwendet.
Dies bedeutet, dass Sie, wenn Sie mit Option 2 beginnen und versehentlich aus dem Max-Hash-Ziplist-Wert ausbrechen, +90 Bytes pro JEDEM ATTRIBUT erhalten, das Sie im Benutzermodell haben! (eigentlich nicht die +90 aber +70 siehe Konsolenausgabe unten)
# 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
....
}
Für die Antwort von TheHippo sind Kommentare zu Option 1 irreführend:
hgetall / hmset / hmget zur Rettung, wenn Sie alle Felder oder mehrere get / set-Operationen benötigen.
Für BMiner Antwort.
Die dritte Option macht wirklich Spaß. Für einen Datensatz mit max (id) <has-max-ziplist-value weist diese Lösung eine O (N) -Komplexität auf, da Reddis überraschenderweise kleine Hashes als Array-ähnlichen Container mit Länge / Schlüssel / Wert speichert Objekte!
Aber oft enthalten Hashes nur wenige Felder. Wenn Hashes klein sind, können wir sie stattdessen einfach in eine O (N) -Datenstruktur codieren, wie ein lineares Array mit Schlüsselwertpaaren mit Längenpräfix. Da wir dies nur tun, wenn N klein ist, beträgt die amortisierte Zeit für HGET- und HSET-Befehle immer noch O (1): Der Hash wird in eine echte Hash-Tabelle konvertiert, sobald die Anzahl der darin enthaltenen Elemente zu groß wird
Aber Sie sollten sich keine Sorgen machen, Sie werden Hash-Max-Ziplist-Einträge sehr schnell brechen und los geht's, Sie sind jetzt tatsächlich bei Lösung Nummer 1.
Die zweite Option wird höchstwahrscheinlich unter einer Haube zur vierten Lösung führen, da die Frage lautet:
Denken Sie daran, dass die Wertelänge nicht vorhersehbar ist, wenn ich einen Hash verwende. Sie sind nicht alle kurz wie das obige Bio-Beispiel.
Und wie Sie bereits sagten: Die vierte Lösung ist mit Sicherheit das teuerste +70 Byte pro Attribut.
Mein Vorschlag, wie man einen solchen Datensatz optimiert:
Sie haben zwei Möglichkeiten:
Wenn Sie die maximale Größe einiger Benutzerattribute nicht garantieren können, entscheiden Sie sich für die erste Lösung, und wenn der Speicher wichtig ist, komprimieren Sie den Benutzer json, bevor Sie ihn in redis speichern.
Wenn Sie die maximale Größe aller Attribute erzwingen können. Dann können Sie Hash-Max-Ziplist-Einträge / Wert festlegen und Hashes entweder als einen Hash pro Benutzerdarstellung oder als Hash-Speicheroptimierung aus diesem Thema eines Redis-Handbuchs verwenden: https://redis.io/topics/memory-optimization und Benutzer als JSON-Zeichenfolge speichern. In beiden Fällen können Sie auch lange Benutzerattribute komprimieren.