Kanru’s 探險日誌

當發現美好的事物時,所要做的第一件事,就是把它分享給所有人

Archive for the ‘msn’ tag

Emesene & SQL Optimization

with 2 comments

最近都是用 emesene 上 MSN,不過他的啟動速度實在是非常慢,啟動的時候硬碟燈狂閃,判斷應該是在讀取聯絡人的資料快取。先用 python profiler 跑過一次,結果果然是 Logger.py 裡面從 sqlite 撈資料的函式在慢。

大小約 17MB 的 db,每個 query 竟然都要一秒以上,難怪 emesene 啟動要這麼久了。就來幫 emesene 最佳化一下 sql 吧。

以底下這個 query 為例:


    select e.stamp, ue.data 
    from event e, user_event ue, user u
    where e.id = ue.id_event and
    u.id = ue.id_user and
    e.name = "status-changed" and
    u.account = "%s"
    order by e.stamp desc
    limit 1

結果是

1221129396.22343|NLN
CPU Time: user 1.173822 sys 0.023997

用 explain query plan 看看


    0|1|TABLE user_event AS ue
    1|0|TABLE event AS e USING PRIMARY KEY
    2|2|TABLE user AS u USING PRIMARY KEY

應該是先把 user_event 與 event, user 三個 table join 在一起,最後再檢查 e.name 與 u.account。

來看看三個 table 的大小

  • user_event: 180801 row
  • event: 192968 row
  • user: 196 row

這樣 join 起來是多大的 table 呀

先試試改寫 from clause 裡的順序


    select e.stamp, ue.data 
    from user u, event e, user_event ue
    where e.id = ue.id_event and
    u.id = ue.id_user and
    e.name = "status-changed" and
    u.account = "%s"
    order by e.stamp desc
    limit 1

結果是

    1221129396.22343|NLN
    CPU Time: user 0.485926 sys 0.008998

很好,時間少了一半,explain query plan 顯示

    0|2|TABLE user_event AS ue
    1|0|TABLE user AS u USING PRIMARY KEY
    2|1|TABLE event AS e USING PRIMARY KEY

如果幫 user_event 建個 index 呢?

    create index ueiduser on user_event(id_user);

再 query 一次

    1221129396.22343|NLN
    CPU Time: user 0.017997 sys 0.004999

快了非常多吧!explain query plan 顯示:

    0|0|TABLE user AS u
    1|1|TABLE user_event AS ue WITH INDEX ueiduser
    2|2|TABLE event AS e USING PRIMARY KEY

這是因為 sqlite 會以 from clause 的第一個當作 outer loop,所以我把數量最小的 user 移到前面,再適當的建立 index,使得 query 的速度快了 100 倍…

參考

Patch 在此

Emesene svn trunk 已經收錄最新 patch :)

Written by Kanru Chen

September 17th, 2008 at 10:27 pm