Sorted Sets
Redis Sorted Set คืออะไร?
หัวข้อที่มีชื่อว่า “Redis Sorted Set คืออะไร?”Sorted Set เหมือน Set แต่สมาชิกแต่ละตัวมี floating-point score Redis รักษาการเรียงลำดับตามคะแนนตลอดเวลาด้วย O(log N) สำหรับการ insert และ range query ถ้าสมาชิกสองตัวมีคะแนนเท่ากัน จะเรียงตาม lexicographic order
ZADD — เพิ่มสมาชิกพร้อมคะแนน
หัวข้อที่มีชื่อว่า “ZADD — เพิ่มสมาชิกพร้อมคะแนน”ZADD key score member [score member ...] เพิ่มสมาชิก ถ้าสมาชิกมีอยู่แล้วคะแนนจะ ถูกอัปเดต คืนจำนวน สมาชิกใหม่ ที่เพิ่ม
127.0.0.1:6379> ZADD game:scores 4200 "alice" 3800 "bob" 5100 "carol"(integer) 3127.0.0.1:6379> ZADD game:scores 4700 "alice"(integer) 0127.0.0.1:6379> ZSCORE game:scores "alice""4700"ZADD game:scores 4200 "alice" 3800 "bob" 5100 "carol"
ZADD game:scores 4700 "alice"
ZSCORE game:scores "alice"ZRANGE และ ZREVRANGE — range ตาม rank
หัวข้อที่มีชื่อว่า “ZRANGE และ ZREVRANGE — range ตาม rank”ZRANGE key start stop [WITHSCORES] คืนสมาชิกตามลำดับคะแนนจากน้อยไปมาก ZREVRANGE คืนตามลำดับจากมากไปน้อย Index เป็น 0-based; -1 หมายถึงสมาชิกสุดท้าย
127.0.0.1:6379> ZADD leaderboard 900 "carol" 1500 "alice" 2100 "bob" 750 "dave"(integer) 4127.0.0.1:6379> ZRANGE leaderboard 0 -1 WITHSCORES1) "dave"2) "750"3) "carol"4) "900"5) "alice"6) "1500"7) "bob"8) "2100"127.0.0.1:6379> ZREVRANGE leaderboard 0 2 WITHSCORES1) "bob"2) "2100"3) "alice"4) "1500"5) "carol"6) "900"ZADD leaderboard 900 "carol" 1500 "alice" 2100 "bob" 750 "dave"
ZRANGE leaderboard 0 -1 WITHSCORES
ZREVRANGE leaderboard 0 2 WITHSCORESZRANK และ ZSCORE — ค้นหาสมาชิก
หัวข้อที่มีชื่อว่า “ZRANK และ ZSCORE — ค้นหาสมาชิก”ZRANK key member คืน rank แบบ 0-based ตามลำดับจากน้อยไปมาก ZREVRANK ให้ rank ตามลำดับจากมากไปน้อย ZSCORE คืนคะแนนเป็น bulk string
127.0.0.1:6379> ZADD players 300 "x" 600 "y" 900 "z"(integer) 3127.0.0.1:6379> ZRANK players "y"(integer) 1127.0.0.1:6379> ZREVRANK players "y"(integer) 1127.0.0.1:6379> ZSCORE players "z""900"ZADD players 300 "x" 600 "y" 900 "z"
ZRANK players "y"
ZREVRANK players "y"
ZSCORE players "z"ZRANGEBYSCORE — range ตามค่าคะแนน
หัวข้อที่มีชื่อว่า “ZRANGEBYSCORE — range ตามค่าคะแนน”ZRANGEBYSCORE key min max [WITHSCORES] ดึงสมาชิกทั้งหมดที่มีคะแนนระหว่าง min และ max (inclusive) ใช้ -inf และ +inf สำหรับขอบเขตเปิด
127.0.0.1:6379> ZADD temps 18.5 "london" 32.1 "bangkok" 24.0 "berlin" 28.7 "tokyo"(integer) 4127.0.0.1:6379> ZRANGEBYSCORE temps 20 30 WITHSCORES1) "berlin"2) "24"3) "tokyo"4) "28.7"ZADD temps 18.5 "london" 32.1 "bangkok" 24.0 "berlin" 28.7 "tokyo"
ZRANGEBYSCORE temps 20 30 WITHSCORESZINCRBY, ZCARD, และ ZREM
หัวข้อที่มีชื่อว่า “ZINCRBY, ZCARD, และ ZREM”ZINCRBY key increment member บวก increment เข้ากับคะแนนของสมาชิกแบบ atomic
ZCARD key คืนจำนวนสมาชิกทั้งหมด
ZREM key member [member ...] ลบสมาชิกหนึ่งตัวหรือมากกว่า
127.0.0.1:6379> ZADD votes 10 "post:1" 5 "post:2" 8 "post:3"(integer) 3127.0.0.1:6379> ZINCRBY votes 3 "post:2""8"127.0.0.1:6379> ZCARD votes(integer) 3127.0.0.1:6379> ZREM votes "post:3"(integer) 1127.0.0.1:6379> ZCARD votes(integer) 2ZADD votes 10 "post:1" 5 "post:2" 8 "post:3"
ZINCRBY votes 3 "post:2"
ZCARD votes
ZREM votes "post:3"
ZCARD votesข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
Sorted Set แทน SQL table + ORDER BY | insert และ range read O(log N) เสมอ ไม่ต้องพึ่ง index ที่ต้อง maintain แยก | คะแนนเป็น float64 เดี่ยวเท่านั้น sort ตามหลายคอลัมน์แบบ relational ทำไม่ได้ตรงๆ |
ZRANGEBYSCORE สำหรับ range query | ดึงข้อมูลตามช่วงคะแนนได้ตรงๆ โดยไม่ต้อง scan ทั้งหมด | ต้องออกแบบ score ล่วงหน้าให้ครอบคลุม use case การ query ทั้งหมด เปลี่ยนทีหลังมีค่าใช้จ่ายในการ re-score |
| tie-break ด้วย lexicographic order เมื่อคะแนนเท่ากัน | พฤติกรรม deterministic ไม่ต้องเขียน logic เพิ่มเมื่อคะแนนชนกัน | ถ้าไม่ได้ตั้งใจออกแบบ member name ให้เรียงมีความหมาย ผลลัพธ์ tie อาจดูสุ่มสำหรับผู้ใช้ |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- คิดว่า
ZADDกับสมาชิกที่มีอยู่แล้วจะสร้าง duplicate — Sorted Set ไม่มีสมาชิกซ้ำ การZADDสมาชิกเดิมจะแค่อัปเดตคะแนนและคืนค่า 0 ไม่ใช่เพิ่มรายการใหม่ - ใช้
ZRANGEเมื่อต้องการลำดับจากมากไปน้อย —ZRANGEเรียงจากน้อยไปมากเสมอ ถ้าต้องการ “คะแนนสูงสุดก่อน” ต้องใช้ZREVRANGEไม่เช่นนั้นผลลัพธ์จะกลับด้าน - ลืมตั้ง
-inf/+infเมื่อต้องการ range แบบเปิดขอบ — การเขียนตัวเลขจำกัดตายตัวในZRANGEBYSCOREแทนที่จะใช้-inf/+infทำให้ query พลาดสมาชิกที่มีคะแนนต่ำ/สูงกว่าที่คาดไว้
💡 ตัวอย่างจากของจริง
Leaderboard และระบบจัดอันดับเกม — ผูก score เข้ากับผู้เล่นโดยตรงเพื่อให้ query “top N” และ “อันดับของฉัน” ทำงานแบบ real-time โดยไม่ต้อง batch คำนวณใหม่
Priority queue และ scheduled job — หลายระบบใช้ Sorted Set ผูก timestamp เป็นคะแนน เพื่อ query “งานที่ถึงกำหนดแล้ว” ด้วย
ZRANGEBYSCOREแทนการ poll ฐานข้อมูลเชิงสัมพันธ์ซ้ำๆ