2016-06-30 13 views
5

Tôi hiện lưu trữ khoảng 50k băm trong bảng Redis của tôi, mỗi cái có 5 cặp khóa/giá trị. Mỗi ngày một lần, tôi chạy lệnh batch để cập nhật giá trị băm, bao gồm thiết lập một số giá trị khóa cho giá trị của khóa khác trong một băm.Redis: cách tốt nhất để có được tất cả các giá trị băm

Đây là mã python của tôi mà lặp thông qua các phím và bộ old_code để new_code nếu giá trị new_code tồn tại cho sự trao băm:

pipe = r.pipeline() 

for availability in availabilities: 
    pipe.hget(availability["EventId"], "new_code") 

for availability, old_code in zip(availabilities, pipe.execute()): 
    if old_code: 
     availability["old_code"] = old_code.decode("utf-8") 

for availability in availabilities: 
    if "old_code" in availability: 
     pipe.hset(
      availability["EventId"], "old_code", availability["old_code"]) 
    pipe.hset(availability["EventId"], "new_code", availability["MsgCode"]) 
pipe.execute() 

Đó là một chút lạ với tôi rằng tôi phải lặp qua các phím hai lần để đạt được cùng một kết quả, có cách nào tốt hơn để làm điều này không?

Một điều khác mà tôi đang cố gắng tìm ra là làm cách nào để có được tất cả các giá trị băm có hiệu suất tốt nhất. Dưới đây là cách tôi đang làm điều đó:

d = [] 
pipe = r.pipeline() 
keys = r.keys('*') 
for key in keys: 
    pipe.hgetall(key) 
for val, key in zip(pipe.execute(), keys): 
    e = {"event_id": key} 
    e.update(val) 
    if "old_key" not in e: 
     e["old_key"] = None 
    d.append(e) 

Vì vậy, về cơ bản tôi keys * sau đó lặp với HGETALL trên tất cả các phím để có được giá trị. Đây là cách quá chậm, đặc biệt là sự lặp lại. Có cách nào nhanh hơn để làm điều đó không?

+0

Bạn có thể giải thích thêm một chút về phần đầu tiên của câu hỏi hay không, Bạn cần làm gì, mà không cần sử dụng bất kỳ ngôn ngữ lập trình nào. – Malinga

+1

http://stackoverflow.com/questions/38065714/is-there-a-command-in-redis-for-hash-data-structure-similar-to-mget/38066688#38066688 kiểm tra câu trả lời của tôi ở đây – Malinga

+0

Đối với mọi băm/hàng Tôi lấy mã hiện tại và lưu nó như new_code, trong khi lưu new_code hiện tại làm old_code (để ghi lại trạng thái trước đó và so sánh old_code và new_code trên mỗi lần kéo dữ liệu). –

Trả lời

5

Làm thế nào về một thay đổi giảm dần. Chuyển đổi cách bạn lưu trữ dữ liệu.

Thay vì có 50k băm mỗi giá trị có 5 giá trị. Có 5 băm mỗi giá trị có giá trị 50k.

Ví dụ băm của bạn phụ thuộc vào EventID và bạn lưu trữ new_code, old_code và chất liệu khác bên băm mà

Bây giờ, cho new_code có một bản đồ băm mà sẽ chứa EventID làm thành viên và giá trị của nó là giá trị. Vì vậy, new_code một mình là một bản đồ băm có chứa 50k giá trị thành viên cặp.

Vì vậy, lặp qua 5 thay vì 50k sẽ tương đối nhanh hơn.

Tôi đã làm một thí nghiệm nhỏ và sau đây là những con số

50k hashes * 5 elements 
Memory : ~12.5 MB 
Time to complete loop through of elements : ~1.8 seconds 

5 hashes * 50k elements 
Memory : ~35 MB 
Time to complete loop through of elements : ~0.3 seconds. 

tôi đã thử nghiệm với chuỗi đơn giản như KEY_i và VALUE_i (trong đó i là các incrementer) để bộ nhớ có thể tăng trong trường hợp của bạn. Và tôi cũng đã đi qua các dữ liệu, tôi đã không thực hiện bất kỳ thao tác nào để thời gian cũng sẽ khác nhau trong trường hợp của bạn.

Như bạn có thể thấy thay đổi này có thể cung cấp cho bạn hiệu suất 5x tăng lên và bộ nhớ lớn hơn 2 lần.

Redis nén cho băm trong phạm vi (512 - mặc định). Vì chúng tôi đang lưu trữ nhiều hơn phạm vi đó (50k), chúng tôi có bộ nhớ tăng đột biến này.

Về cơ bản, đó là giao dịch và bạn có thể chọn tùy chọn phù hợp nhất cho ứng dụng của mình.

Đối với câu hỏi 1 của bạn:

  1. bạn đang nhận được giá trị của new_code trong mỗi băm, bây giờ bạn có tất cả mọi thứ trong một hash duy nhất -> chỉ là một cuộc gọi duy nhất.
  2. Sau đó, bạn đang cập nhật old_code và new_code từng cái một. Bây giờ bạn có thể làm chúng bằng cách sử dụng hmset bằng một cuộc gọi duy nhất.

Hy vọng điều này sẽ hữu ích.

0

Không có lệnh như vậy, băm redis hoạt động bên trong hàm băm, vì vậy HMGET hoạt động bên trong một băm và cung cấp tất cả các trường trong băm đó. Không có cách nào để truy cập tất cả các trường trong nhiều băm tại.

Có 2 lựa chọn

  1. Sử dụng đường ống
  2. Sử dụng LUA

Tuy nhiên cả hai điều này là cách giải quyết, không phải là một giải pháp cho vấn đề của bạn. Để biết cách thực hiện việc này, hãy kiểm tra Câu trả lời của tôi trong Câu hỏi này: Is there a command in Redis for HASH data structure similar to MGET?

2

Đối với vấn đề đầu tiên của bạn, sử dụng kịch bản Lua chắc chắn sẽ cải thiện hiệu suất. Điều này chưa được kiểm tra, nhưng có điều gì đó như:

update_hash = r.register_script(""" 
    local key = KEYS[1] 
    local new_code = ARGS[1] 

    local old_code = redis.call("HGET", key, "new_code") 
    if old_code then 
     redis.call("HMSET", key, "old_code", old_code, "new_code", new_code) 
    else 
     redis.call("HSET", key, "new_code", new_code) 
    end 
""") 

# You can use transaction=False here if you don't need all the 
# hashes to be updated together as one atomic unit. 
pipe = r.pipeline() 

for availability in availabilities: 
    keys = [availability["EventId"]] 
    args = [availability["MsgCode"]] 

    update_hash(keys=keys, args=args, client=pipe) 

pipe.execute() 

Đối với vấn đề thứ hai, bạn có thể làm nhanh hơn bằng cách viết kịch bản Lua ngắn. Thay vì nhận tất cả các khóa và trả lại cho khách hàng, tập lệnh của bạn sẽ nhận được các khóa và dữ liệu được liên kết với họ và trả lại trong một cuộc gọi.

(Lưu ý, tuy nhiên, gọi số keys() vốn đã chậm ở bất cứ nơi nào bạn làm điều đó. Và lưu ý rằng trong cả hai cách bạn đang kéo toàn bộ tập dữ liệu Redis của bạn vào bộ nhớ cục bộ, có thể hoặc không trở thành vấn đề.)

Các vấn đề liên quan