首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

Redis Sorted Set (ZSET) 實戰筆記:從 3000 萬行 MySQL 取 Top 10 熱門路徑

     編輯:MySQL 綜合教學

業務場景

MySQL 表 summary_data 約 3000 萬行,欄位 first_path VARCHAR(256),需找出現次數最多的 Top 10 路徑。

方案一:純 SQL(9 分鐘)

SELECT first_path, COUNT(*) AS c
FROM summary_data
GROUP BY first_path
ORDER BY c DESC LIMIT 10;

EXPLAIN 顯示 type=ALL、Using temporary; Using filesort,索引 first_path(255) 前綴過長導致失效,全表掃描 + 磁碟排序極慢。

方案二:Linux Sort + Uniq(1.5 分鐘)

# 導出 first_path(耗時較長)
SELECT first_path FROM summary_data INTO OUTFILE '/tmp/first_path.txt';

# 管道處理
sort /tmp/first_path.txt | uniq -c | sort -nr | head -10

外部排序優化極佳,記憶體不足自動落盤歸併,單線程 1.5 分鐘完成。

方案三:Redis Sorted Set(16 分鐘,待優化)

資料結構

  • ZSET = Skip List + Hash Table 混合體。
  • 元素 = first_path 字串,Score = 出現次數 (double)。
  • ZINCRBY key 1 member 原子遞增,自動維護有序。O(log N)。

C 客戶端實現

/* hiredis 例程 */
FILE *fp = fopen("first_path.txt", "r");
char line[256];
while (fgets(line, sizeof(line), fp)) {
    // 去除換行
    line[strcspn(line, "\r\n")] = 0;
    redisCommand(c, "ZINCRBY zset_firstpath 1 %s", line);
}
fclose(fp);

/* 取 Top 10 */
redisReply *r = redisCommand(c,
    "ZREVRANGEBYSCORE zset_firstpath +inf -inf WITHSCORES LIMIT 0 10");
/* 輸出:
1) path_a  12345
2) path_b  9876
... */

效能分析

  • 3000 萬次 ZINCRBY 網路往返 + Skip List 維護 = 16 分鐘,**慢於 Sort/Uniq**。
  • Redis 單線程模型,CPU 為瓶頸;管道 pipeline 批量發送可大幅提升(未測試)。
  • 記憶體佔用:3000 萬唯一值 × (字串 + 分數 + 指標) ≈ 數 GB,需評估機器容量。

最佳實踐總結

優化建議

  1. **管道批量寫入**:redis-cli --pipe < commands.txt 或 hiredis redisAppendCommand 批量提交,減少 RTT。
  2. **Lua 腳本原子化**:將讀取+遞增合併為單次 EVAL,減少網路交互。
  3. **分片**:多 Redis 實例按 Hash 分片,聚合時合併結果。
  4. **MySQL 8.0 並行查詢 / 物化視圖**:若業務允許定時刷新,物化視圖 + 索引可秒級查詢。

ZSET 適合**實時排行榜**(遊戲積分、熱門商品),離線全量統計仍首選 **Sort/Uniq 或 ClickHouse/Druid 等 OLAP 引擎**。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方案耗時優點缺點
MySQL GROUP BY9 分鐘零外部依賴全表掃描、臨時表、磁碟排序
Sort + Uniq1.5 分鐘極速、無額外基建需導出檔案、單機單線程
Redis ZSET16 分鐘支援實時增量更新、范圍查詢載入慢、記憶體大、單線程 CPU 瓶頸