[Python] Redis v.s Mysql 查詢實作

PC Chen
程式乾貨
Published in
5 min readJan 30, 2021

第一次接觸 Redis 時,是工作上需要撈取後端同事儲存在上面的資料,當時天真的我都覺得為什麼資料不全部放在資料庫(Mysql, MariaDB)就好?這樣我都去同一個資料源撈就好XD

事實上,後端在開發時會儲存許多不同類型的資料,並不是所有的資料都適合儲存在資料庫中(疑?那不然要存在哪裡?),依照不同的使用場景會儲存在不同的地方,redis 就是其中一個地方~

使用場景

讓我們簡單想像一個情境,假設現在後端開發一個「登入系統」,就是我們最常見的讓使用者輸入「帳號」及「密碼」、做一個登入的動作!
那可想而知一定要有個地方去儲存使用者帳號對應的密碼,所以我們先簡單地都放進 mysql 資料庫吧~

再多想一步

把所有帳號密碼都丟進資料庫這樣真的好嗎?假設今天這個系統有很多使用者、而且大家都頻繁地上線登入,這樣就代表資料庫會被頻繁地查詢。如果帳號一多,資料庫一定會被查到炸掉,所以這樣是不行滴~

Redis cache 的妙用

為什麼資料庫頻繁地被查會炸掉呢?其實資料庫儲存結構是在電腦「硬碟」上,除了搜尋資料速度比較慢之外、頻繁地去硬碟掃資料也容易造成鎖死lock 的情形,而 redis 的 cache快取 儲存方式就恰恰解決了這個問題。

快取簡單的想像就是將資料儲存在電腦「記憶體」中,如果資料是頻繁要去查詢的,存在記憶體中可以讓電腦快速地找到。更白話一點就是如果這些資料是 已經 查詢過的,就先把它們保留在一個小角落,等到有新的請求是要求看已經查詢過的資料,就可以用極快的速度從小角落拿出來、而不用再去倉庫(資料庫)中翻箱倒櫃重新找出來一次。

這個小角落,其實就是 Redis 啦~~

實作情境

今天我們一樣來寫個 python 程式模擬登入系統:現在有許多使用者輸入了「帳號」,而網站收到了帳號會去尋找對應的「密碼」,步驟如下:

  1. 先嘗試從 redis 拿取密碼X。如果找到密碼就回傳值。
  2. 如果 步驟1 拿不到密碼,就去 mysql 裡面找。如果找到密碼 X 就在回傳後、寫一筆到 redis 中;
  3. 如果 步驟2 在 mysql 也找不到密碼,就寫一筆到 mysql 中、並同時也寫一筆到 redis 中,最後回傳密碼。

感覺上很複雜,簡單想就是不管怎樣查資料一定會先從 redis 查,如果查不到才會去 mysql 查。如果連 mysql 都查不到代表一開始沒有建檔,所以要寫一筆進去 mysql 中,中間查詢的過程也都會另外寫一筆到 redis 做快速查詢。

準備工作

首先我們需要安裝好 Redis 與 Mysql,macOS 可以簡單使用 HomeBrew 安裝就好,今天重點先擺在 python實作部分,詳細安裝可自行google關鍵字:「安裝 mysql redis」,都有很多詳細資訊~

安裝好 mysql 後,我們先進入 mysql server 後,並在 localhost 建立一個 database: test,然後建立一張表 tb_user 專門用來記錄帳號密碼表。可參考以下程式碼:

小~小~的背景知識

或許你又會想問:「咦我們現在又沒有真正的使用者申請,怎麼做到模擬的密碼?」,這篇因為只是要模擬而已,假設我有100個使用者,那我就會隨機在 1-100 之間挑一個數當作帳號,然後把該帳號輸入 sha-256雜湊函數,將函數輸出的值當作密碼。
有在接觸區塊鏈的讀者應該不陌生,沒聽過的讀者也不用緊張,可以把它想像成是一個輸入字串、最後輸出會是長度32的字串,而且是一對一的關係,就很像「帳號」對應「密碼」的關係~
例如我輸入一個字串"a",sha256就會吐一個字串"0cc175b9c0f1b6a831c399e269772661",其他輸入字串都不可能得到跟字串"a"一樣的結果。python 中有 hashlib 這個函式可以操作,大家可以先參考下面的程式碼玩玩看:

# 字串 "a" 輸出結果
0cc175b9c0f1b6a831c399e269772661

正式開始

首先

我們先使用 python 連入本地端的 redis 與 mysql:

再來我們寫一個計時器,當作之後函數運行的 decorator ,讓我們可以對函數的運行進行計時,方便之後做運行速度的比較~

模擬 redis + mysql 查詢

進入重頭戲,我們來實作上面一開始所說的,先使用 redis 當快取緩存、如果查不到資料再去 mysql 裡面查詢。
一開始的參數設定,我預設有 100 位使用者 、並且 隨機重複查詢 10000 次 ,另外在一開始會先把 redis 與 mysql 的資料做清除,為了測試的公平性~

模擬只用 mysql 查詢

對照組我們就每次查詢都只去 mysql 查詢,如果沒有查到就在 mysql 寫一筆:

速度運行大PK

程式碼都刻完,現在我們寫一個腳本來呼叫函數執行吧~
用肉眼看好像 redis + mysql 的程式碼複雜許多,到底誰會比較快呢?

執行腳本的結果:

我們發現,搭配 redis 的速度快上許多,尤其是如果短時間隨機查詢到了 100000 次時,如果只用 mysql 查詢竟然要超過一分鐘。這個如果是大型網站,絕對會被使用者靠北到不行XD

詳細的程式碼一樣放在我的 github,有興趣的讀者可以自行下載玩玩看

延伸閱讀

細心的讀者會發現也想問的是:「奇怪一開始在 mysql 建的表中,其實有在 account 上面打 index索引,那為什麼查詢還是會慢呢?」

這其實牽涉到資料結構的問題,在 mysql 資料庫中索引的結構式使用 B+ tree,假設現在帳號資料有 n 筆,那查詢的時間複雜度是 O(logn)。

但是在 redis 中因為是 key-value 的儲存方式,因使不管資料筆數多少、查詢的時間複雜度都是 O(1)。可想而知若能適時地將一些 熱資料 存進 redis、把 冷資料 存進 mysql 中,將會增加不少查詢的效率。

--

--

PC Chen
程式乾貨

喜歡接觸與動手實作各種軟體技術的後端數據工程師 A data- backend engineer who is enthusiastic in learning and implementing any techniques in software engineering.