Beberapa tambahan pada serangkaian jawaban yang diberikan:
Pertama-tama, jika Anda akan menggunakan hash Redis secara efisien, Anda harus tahu kunci menghitung jumlah maksimum dan nilai ukuran maksimum - jika tidak, jika hash-max-ziplist-value atau hash-max-ziplist-entries Redis akan mengubahnya menjadi praktis pasangan kunci / nilai biasa di bawah tenda. (lihat hash-max-ziplist-value, hash-max-ziplist-entri) Dan melanggar di bawah tenda dari opsi hash BENAR-BENAR BURUK, karena setiap pasangan kunci / nilai biasa di dalam Redis menggunakan +90 byte per pasang.
Ini berarti bahwa jika Anda mulai dengan opsi dua dan tanpa sengaja keluar dari nilai max-hash-ziplist-Anda akan mendapatkan +90 byte per SETIAP ATTRIBUTE yang Anda miliki di dalam model pengguna! (sebenarnya bukan +90 tetapi +70 lihat output konsol di bawah)
# 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
....
}
Untuk jawaban TheHippo, komentar pada Opsi satu menyesatkan:
hgetall / hmset / hmget untuk menyelamatkan jika Anda membutuhkan semua bidang atau operasi beberapa get / set.
Untuk jawaban BMiner.
Pilihan ketiga sebenarnya sangat menyenangkan, untuk dataset dengan max (id) <memiliki-max-ziplist-value solusi ini memiliki kompleksitas O (N), karena, yang mengejutkan, Reddis menyimpan hash kecil sebagai wadah array seperti panjang / kunci / nilai benda!
Tetapi berkali-kali hash hanya berisi beberapa bidang. Ketika hash berukuran kecil, kita bisa mengkodekannya dalam struktur data O (N), seperti array linier dengan pasangan nilai kunci yang diawali dengan panjang. Karena kita melakukan ini hanya ketika N kecil, waktu diamortisasi untuk perintah HGET dan HSET masih O (1): hash akan dikonversi menjadi tabel hash nyata segera setelah jumlah elemen yang dikandungnya akan tumbuh terlalu banyak
Tetapi Anda tidak perlu khawatir, Anda akan memecahkan entri hash-max-ziplist-sangat cepat dan di sana Anda sekarang Anda benar-benar di solusi nomor 1.
Opsi kedua kemungkinan besar akan menuju solusi keempat di bawah tudung karena sebagai pertanyaan menyatakan:
Perlu diingat bahwa jika saya menggunakan hash, panjang nilainya tidak dapat diprediksi. Mereka tidak semuanya pendek seperti contoh bio di atas.
Dan seperti yang sudah Anda katakan: solusi keempat adalah +70 byte paling mahal untuk setiap atribut.
Saran saya bagaimana mengoptimalkan dataset tersebut:
Anda punya dua opsi:
Jika Anda tidak dapat menjamin ukuran maksimal beberapa atribut pengguna daripada Anda mencari solusi pertama dan jika masalah memori sangat penting daripada kompres pengguna json sebelum disimpan dalam redis.
Jika Anda dapat memaksa ukuran maksimum semua atribut. Daripada Anda dapat mengatur hash-max-ziplist-entri / nilai dan menggunakan hash baik sebagai satu hash per representasi pengguna ATAU sebagai optimasi memori hash dari topik ini panduan Redis: https://redis.io/topics/memory-optimization dan menyimpan pengguna sebagai string json. Bagaimanapun Anda juga dapat mengompres atribut pengguna yang panjang.