昨天說這三十天從一疊紙卡開始。今天就從那疊卡片開始。
社區轉角的租書店開了很多年。每位會員一張會員卡;每本書的封底貼一個小紙袋,裡面插一張借閱卡。客人借書,店員在借閱卡上寫下會員編號和借出日期,把卡抽出來插進櫃檯的卡片盒;還書的時候再把那張卡找出來,打個勾,插回書裡。
老闆當年這樣設計的時候,店裡只有兩百多本書,卡片盒一眼看得到底。
現在藏書幾百本、會員幾十位,同一套做法開始每天讓人皺眉。
卡片盒依書名排。客人把書放在櫃檯上,店員照書名翻到那一張,抽出來,很快。
但會員一問「我借了哪幾本、什麼時候要還」,店員就得把整盒從頭翻到尾——卡片是按書排的,同一位會員的卡散在盒子各處。
店裡真的試過改成依會員排。查詢變快了,換成還書的時候不知道該抽哪一張。
依書名排 → 還書快 查某位會員借了什麼 慢
依會員排 → 查詢快 還書要找那一張 慢
同一疊卡片,同一位店員,換一種排法,快的那件事和慢的那件事就互換。
這就是索引要解的問題:同一份資料只能照一種順序擺,店員卻要從兩個方向找。這個困境不是資料庫帶來的,在有電腦之前它就已經插在卡片盒裡了。
資料庫的做法不是每次把原資料重排,而是另外維護一個查找入口。代價也很清楚:多存一份查找結構,而且每次寫入都要一起維護它。第二十天會在SQLite上建一個索引,順便回答一件更尷尬的事——建了,不代表資料庫一定會用它。
老闆問能不能寫成程式。筆者這邊沒有先畫資料表,先做的是一件更笨的事:把紙卡上實際寫著的欄位一個一個抄下來。
| 紙卡上的欄位 | 寫在哪張卡 | 天然歸屬 |
|---|---|---|
| 書名、作者、ISBN | 封底借閱卡的上緣 | 書 |
| 會員編號、姓名、電話 | 會員卡 | 會員 |
| 會員編號、借出日期、歸還日期 | 借閱卡上的每一行 | 一次借還 |
抄完,它們自己分成三組:書、會員、一次借還。
三個名詞不是設計出來的。老闆當初做卡片的時候就已經分好了,筆者只是把它認出來。這和昨天那張十幾張資料表的ER圖差在哪裡:那張圖上的「預約」「會員等級」「庫存異動」,這家店的卡片上一個字都沒有。
有一件事筆者現在故意不碰:同一本書買了兩本的時候,兩張借閱卡各自插在各自的書裡,紙卡自己分得清楚,程式不一定分得清楚。這件事第六天會真的發生,那時再解。
候選有四個:改變紙卡排法、用試算表、訂閱現成的租書店軟體、自己寫一套。
今天的決定是:先不寫程式,也不選工具。
看起來像沒做事,但這一階段要看的只有三件事——現在要多花多少錢、店員要不要改變習慣、下一步還能不能換方向。第三件最難反悔:現在挑定一套軟體,店裡的流程就得跟著它改。目前只知道兩種排法各有一邊要慢慢找,還沒有人比過哪一個卡點最值得先解。
「自己寫程式」大概會是最後走的路,但在它和試算表被放在同一個問題上比過之前,那只是一種偏好,不是決策。試算表這條路第五天會真的做一版出來。
三個名詞有了,下一步不是開始寫櫃檯程式,是先做一個種子資料產生器——固定隨機種子,S、M、L 三種規模。之後每一次量測都用同一組資料,數字才比得出差別。
昨天說每個數字都要自己量。量之前要先確定,兩次量的是同一家店。
這個系列是筆者正在寫的一套教學內容的濃縮版;完整版含每一次量測的原始輸出與更長的決策紀錄,三十天結束後會繼續往下走。