漂J
遇到一個簡單的(?)MySQL 問題,到底應該 INSERT 還是 UPDATE,對資料庫效能的衝擊才能降到最低啊
漂J
假設有個機器人,使用者可以跟機器人對話,每次對話的時候對話的使用者的 ID 跟時間都會被記錄到資料庫。

每天會從資料庫撈出 24 小時內有跟機器人對話過至少一次的使用者的清單 (每天只會撈一次)
漂J
這樣到底該每次使用者對話都 INSERT 一次,還是 UPDATE 最後對話的時間就好
Tsuki-勝ったな、ガハハ!
insert on duplicate key update
Tsuki-勝ったな、ガハハ!
我不清楚該table是否有其他query需求
達人🐉☄️💫
我選後者
漂J
Tsuki-勝ったな、ガハハ! : 現在的確是用 insert on duplicate key update 沒錯,表應該算滿常被 query 的,但 update 的頻率應該相對比較低
Tsuki-勝ったな、ガハハ!
所以主要的負擔是Read,不是Write?
漂J
這倒是好問題,沒有認真研究過
漂J
應該 read 多一些, write 應該只集中在特定時段
Tsuki-勝ったな、ガハハ!
這樣的效能最佳化有點玄
漂J
一張 table 塞了三種類型的 record
感覺省了 schema 卻拖累效能
漂J
算了還是別想太多,繼續用 insert on duplicate key update 應該即可?
日 落
「到底應該 INSERT 還是 UPDATE,對資料庫效能的衝擊才能降到最低」
如果問題是這個的話,我建議 always insert,印象中 b-tree 在 insert 的時候最多只要預先分配空間,update 的話好像要重建
漂J
日 落 : 我也印象中某些論點是這樣說,但多方查詢資料後,好像也不是總是如此
日 落
日 落
漂J
感覺我沒定義清楚,如果要 INSERT 應該就要開另外一張 table,然後只做 INSERT
日 落
日 落
我不是很清楚你目前的問題和運作環境,除非差異很大,不然我會先考慮維護成本,效能問題花錢解決快很多
漂J
維護成本的話,我感覺好像還是 UPDATE 的版本好些
畢竟 code 都寫好了,只是突然有點越想越不對勁
這樣也不用再多開一張 table,只要修改原本 table schema 就好
日 落
我想確認一下,目前在討論的是「對話記錄」的 table?還是「使用者統計」的 table?
Mr. Push
如果你那張表的欄位寬度沒到很寬,我會覺得 update 比較好,InnoDB 本身有對 page 做 cache,如果是短時間互動頻率高的話這些熱頁會一直躺在記憶體力,把耗時的 I/O 壓到最低,但如果是一直 Insert 的話,會產生很多的 I/O,如果互動頻率高到來不及 I/O 的話你的整個 DB 會卡住,不過我覺得對話記錄 9 成 99 會再拿來做其它分析啦... 先存起來不見得是壞事 =w=
漂J
日 落 : 主要是作對話紀錄跟使用者的狀態紀錄沒錯 其實一張表有好幾個用途,統計的部分基本上是一天作一次
漂J
咦不對我在講什麼 = = 這樣跟上面的講的讀多寫少好像又不一樣了
日 落
漂J : 你該睡了
Tsuki-勝ったな、ガハハ!
他這時間正要開始工作
漂J
Mr. Push : 把對話紀錄存起來的確有考慮到事後可以再拿來分析的可能,雖然我覺得真正用到的機會不大。Insert 的 I/O 會產生比較多這個我倒是沒想到...
漂J
仔細想想,這張表果然還是寫入的頻率比較高,讀取應該還是略少於寫入
漂J
自作聰明把 schema 擴充想節省 table 結果搞到表的用途越來越複雜的下場
l• ܫ•) Davyキュルッ
你這種就是標準的寫 log 啊
這種時候應該是考慮換 DB 而不是繼續用 MySQL

btw, 我選 update,因爲 insert 是 table lock,update 有機會做到 row lock
l• ܫ•) Davyキュルッ
對了,你已經遇到效能衝擊而需要開始思考最佳化的問題了嗎? 如果沒有的話,就放置啊
漂J
l• ܫ•) Davyキュルッ : 我有想過其實應該很適合用 Redis,但怕增加以後架構維護的複雜度而作罷
漂J
原來 insert 會 table lock
漂J
效能衝擊算稍微遇到,之前因為這樣把 Cloud SQL 的硬體配置加大,但是想想也不是長久之計
漂J
因為是沒寫入也不會真的影響太大的東西,所以就算 Redis 不幸爛掉又復原不了也不會怎樣,頂多那天不要統計數據 (現在每天手動跑也常常忘記),但就卡在我覺得這樣架構變複雜對未來不知道是不是好事…
漂J
但說真的其實變複雜好像也沒差,反正現在本來就有服務依賴 Redis,硬幹多增加另一個會寫入 Redis 的設計好像也不會有人阻止我
漂J
反正都有現成的 Redis 了,不用白不用,架構變複雜也不一定是壞事吧
l• ܫ•) Davyキュルッ
怎麼會用 redis...
適合存 log 的 db 這麼多
而且你是集中在一個時間統計
直接存到檔案裡面用 awk sed perl 之類的處理都比較快
l• ܫ•) Davyキュルッ
innodb 是有想辦法避開這種 lock 但如果你的 id 是 AI 的話還是會需要整張 lock
漂J
l• ܫ•) Davyキュルッ : 因為 Infra 現在就已經有 Redis 啦,不用再多增加第三種 DB 讓架構更複雜
漂J
嚴格說起來只是存一個數值而已,核心需求是存跟使用者最新一次對話的時間點,因為本來想說反正都有可能要 INSERT 了,不如把整個對話的內容也一起存起來
漂J
user_id | last_update_time 大概就存這兩個欄位是關鍵而已
l• ܫ•) Davyキュルッ
我有看懂哇 不用一直重複吧XDD
l• ܫ•) Davyキュルッ
是說你這個問題 是不是好幾天前也問過了
漂J
l• ܫ•) Davyキュルッ : 沒吧 難道我穿越了
l• ܫ•) Davyキュルッ
有吧 幾個月前
漂J
沒印象了,已從短期記憶被 flush 掉
l• ܫ•) Davyキュルッ
漂J
喔喔原來是這兩則噗啊 得證我會上來發廢噗的都是同一個專案欸
最後都參考噗友的建議行事了
除了 transaction 的沒有辦法完全做到以外
漂J
不過問題還是不完全一樣吧,只是都跟 DB 有關
漂J
Want to use Redis as an events statistics store
發現用 Redis 來處理好像也頗不好使
漂J
而且如果用 ZADD 還有要排程刪除過期資料的問題
載入新的回覆