Redis Hashes (Part 2)
This lesson covers numeric operations on hash fields, iterative queries, and other advanced features.
HINCRBY: Increment Field Values
Hash fields can store numeric strings and support atomic arithmetic operations.
HINCRBY: Integer Increment
REDIS
# Create article statistics
HSET article:123 views 1000 likes 50 comments 20
# Increment view count
HINCRBY article:123 views 1
(integer) 1001
# Increment like count
HINCRBY article:123 likes 1
(integer) 51
# Batch increment
HINCRBY article:123 views 10
(integer) 1011
# Decrement (pass a negative number)
HINCRBY article:123 likes -1
(integer) 50
HINCRBYFLOAT: Floating-Point Increment
REDIS
# Product price
HSET product:2001 price 99.99
# Increase price
HINCRBYFLOAT product:2001 price 10.5
"110.49"
# Decrease price (pass a negative number)
HINCRBYFLOAT product:2001 price -5.0
"105.49"
Use Case: Counter Group
REDIS
# User statistics
HSET user:stats:1 posts 0 followers 0 following 0
# Publish an article
HINCRBY user:stats:1 posts 1
# Gain a follower
HINCRBY user:stats:1 followers 1
# Follow someone
HINCRBY user:stats:1 following 1
# View statistics
HGETALL user:stats:1
💡 Advantage: Using a hash to store multiple counters is more memory-efficient than using multiple string keys.
HSCAN: Iterate Through Large Hashes
When a hash has many fields, HGETALL returns all data at once, which can block the server. HSCAN allows batch iteration.
Basic Usage
REDIS
# Create a large hash
HSET large:hash field1 "value1" field2 "value2" ... field1000 "value1000"
# Start iteration
HSCAN large:hash 0
1) "127" # Cursor for next iteration
2) 1) "field1"
2) "value1"
3) "field2"
4) "value2"
...
# Continue iteration
HSCAN large:hash 127
1) "0" # Cursor of 0 means iteration is complete
2) 1) "field999"
2) "value999"
...
Match Pattern
REDIS
# Get only fields matching a pattern
HSCAN user:1 0 MATCH age*
1) "0"
2) 1) "age"
2) "25"
Specify Count Per Iteration
REDIS
# Return approximately 100 fields per iteration
HSCAN large:hash 0 COUNT 100
💡 Use case: HSCAN is great for iterating through large hashes without blocking the server.
Advanced Hash Applications
Use Case 1: E-commerce Product Details
REDIS
# Store full product info
HSET product:3001 \
name "iPhone 15 Pro" \
brand "Apple" \
price 8999 \
stock 100 \
category "phone" \
sales 0 \
rating 4.8
# View basic product info
HMGET product:3001 name price stock
# Increment sales
HINCRBY product:3001 sales 1
# Decrement stock
HINCRBY product:3001 stock -1
# Update rating
HSET product:3001 rating 4.9
# Check stock
HGET product:3001 stock
Use Case 2: User Configuration
REDIS
# Store user config
HSET user:config:1 \
theme "dark" \
language "en" \
notifications "on" \
privacy "public" \
timezone "America/New_York"
# Get a single config
HGET user:config:1 theme
# Modify a config
HSET user:config:1 theme "light"
# Batch get configs
HMGET user:config:1 theme language notifications
Use Case 3: Real-time Statistics
REDIS
# Daily site statistics
HSET stats:20260623 \
page_views 0 \
unique_visitors 0 \
new_users 0 \
orders 0 \
revenue 0.0
# Increment page views
HINCRBY stats:20260623 page_views 1
# Increment unique visitors
HINCRBY stats:20260623 unique_visitors 1
# Increment orders
HINCRBY stats:20260623 orders 1
# Increment revenue
HINCRBYFLOAT stats:20260623 revenue 299.99
# View statistics
HGETALL stats:20260623
Use Case 4: A/B Test Configuration
REDIS
# Store experiment config
HSET experiment:homepage \
button_color "blue" \
layout "grid" \
show_banner "yes" \
discount_rate 0.1
# Get experiment config
HGET experiment:homepage button_color
# Update experiment config
HSET experiment:homepage button_color "red"
Hash vs JSON Comparison
Storage Comparison
Method 1: Hash
REDIS
HSET user:1 name "Alice" age 25 email "alice@example.com"
Method 2: String JSON
REDIS
SET user:1 '{"name":"Alice","age":25,"email":"alice@example.com"}'
Operation Comparison
| Operation | Hash | String JSON |
|---|---|---|
| Get single field | HGET user:1 name |
Need to parse JSON |
| Modify single field | HSET user:1 age 26 |
Read → parse → modify → serialize → write back |
| Get all fields | HGETALL user:1 |
GET user:1 + parse JSON |
| Numeric operation | HINCRBY user:1 age 1 |
Need to parse → modify → serialize |
| Memory usage | Smaller | Larger (JSON format overhead) |
Use Case Comparison
| Scenario | Recommended | Reason |
|---|---|---|
| User profile | Hash | Independent fields, frequent updates |
| Product info | Hash | Independent fields, partial updates |
| Complex nested objects | String JSON | Hash does not support nesting |
| Array data | String JSON | Hash does not support arrays |
| Configuration object | Hash | Independent fields, fast queries |
💡 Selection principle:
- Independent fields, frequent partial updates → Hash
- Complex nesting, arrays needed → String JSON
- Numeric operations needed → Hash
Performance Optimization
1. Avoid Large Hashes
REDIS
# ❌ Not recommended: single hash with too many fields
HSET big:hash field1 ... field10000
# ✅ Recommended: shard into multiple hashes
HSET hash:part1 field1 ... field1000
HSET hash:part2 field1001 ... field2000
2. Use HSCAN Instead of HGETALL
REDIS
# ❌ HGETALL on large hash
HGETALL large:hash # May block
# ✅ Use HSCAN for iteration
HSCAN large:hash 0
3. Batch Operations Reduce Network Round Trips
REDIS
# ❌ Multiple individual operations
HSET user:1 name "Alice"
HSET user:1 age 25
HSET user:1 city "Beijing"
# ✅ Batch operation
HSET user:1 name "Alice" age 25 city "Beijing"
4. Configure Encoding Thresholds
In redis.conf:
CONF
# Hash field count threshold (default 512)
hash-max-ziplist-entries 512
# Hash field value max length (default 64 bytes)
hash-max-ziplist-value 64
ℹ️ Note: Increasing thresholds can save memory but may reduce performance. Adjust based on your actual data.
Hash Limitations
1. No Nesting Support
REDIS
# ❌ Cannot store nested objects directly
HSET user:1 address '{"city":"Beijing","zip":"100000"}'
# ✅ Use string for nested parts
HSET user:1 city "Beijing" zip "100000"
2. No Array Support
REDIS
# ❌ Cannot store arrays
HSET user:1 tags ["redis","database","cache"]
# ✅ Use set or list for arrays
SADD user:1:tags "redis" "database" "cache"
3. Values Can Only Be Strings
REDIS
# All values are strings
HSET user:1 age 25
HGET user:1 age
"25" # Returns string, not integer
❓ FAQ
Q What happens if HINCRBY is used on a non-numeric field?
A It returns an error:
(error) ERR hash value is not an integer. Make sure the field value is a numeric string.Q Are hash fields ordered?
A No. Hash fields are unordered — HGETALL does not guarantee any specific order.
Q How do I check if a key is a hash type?
A Use the TYPE command:
TYPE user:1 returns hash.Q Does HSCAN guarantee no duplicates?
A No. HSCAN may return duplicate fields — the application layer needs to handle deduplication.
Q What's the difference between hash and set?
A A hash stores field-value pairs; a set stores unique elements. Hashes are for objects, sets are for tags and relationships.
📖 Summary
- HINCRBY/HINCRBYFLOAT perform numeric operations on fields
- HSCAN iterates through large hashes, avoiding blocking
- Hashes are suitable for products, configs, statistics objects
- Hash vs JSON string: Hash for simple objects with partial updates
- Performance tips: avoid large hashes, use HSCAN, batch operations
- Hash limitations: no nesting, no arrays, values are strings only
📝 Exercises
- Numeric operations: Use a hash to store article stats (views, likes, comments) and increment with HINCRBY
- Product management: Use hash to store product info, practice viewing, modifying, incrementing sales, decrementing stock
- Configuration management: Use hash for user config, practice getting single config, batch get, and modifying configs
- Performance comparison: Compare the steps for modifying a single field using hash vs String JSON
Next Lesson
In the next lesson, we will learn Redis Lists (Part 1), covering basic list operations.



