2010年2月4日 星期四

google app engine data store query的bug!! data missing

這是一個很嚴重的bug
在data store裡有夠多資料而且有建立index時
某些情況下用帶有"order by"的gql語法query資料 會回傳不正確的結果
舉例來說資料如果是長這樣
name id score
aaa 111 10
bbb 222 7
aaa 333 15
aaa 444 20
aaa 555 7
bbb 666 1

query "SELECT * FROM targetDB WHERE name = 'aaa'"
結果會有4個
aaa 111 10
aaa 333 15
aaa 444 20
aaa 555 7

在query "SELECT * FROM targetDB WHERE name = 'aaa' ORDER BY score DESC"
預期結果應該長這樣(看score遞減排序)
aaa 444 20
aaa 333 15
aaa 111 10
aaa 555 7

但神奇的是有時候出來的結果不是這樣 可能會少一個兩個
例如變成
aaa 444 20
aaa 111 10
aaa 555 7

甚至只出現
aaa 111 10

而且消失的結果不見了就不會再出現 不管你重新query幾百次都一樣... 甚至index整個砍掉rebuild也於事無補!!
那個消失的資料不是真的不見 它還是在data store中 只是不會再出現在帶有"order by"的query結果裡
所以如果直接"SELECT * FROM targetDB" 還是能看的到消失的資料

目前猜測是因為google專屬的big table存放特性的關係
官方index的說明中有一段這樣的解釋
"為取得符合不等式篩選器的所有結果,查詢會掃描索引表格,找到第一個符合的列,再傳回所有連續的結果,直到找到不符合的列為止。如要使用連續列做為完整的結果集,這些列必須在其他排序順序之前,先依照不等式篩選器排序。"

我猜測會造成這個bug是因為在建立資料後 有更動到index
GAE在建立新index時 並沒有完全的把所有資料行都重新index
可能有些資料行沒被更新到會落單(正常來說符合index條件的資料行要被連續放置在相鄰的空間) 這些落單資料行我暫時稱為"碎片"
在新增資料時 GAE會去尋找符合的index來決定要把新資料放在那個地方(要與同樣符合index條件的舊資料相鄰) 但在找時 又有一定的機率會找到"碎片" 然後就放在"碎片"旁邊 於是"碎片"就變大了
在query時 因為會找到第一個符合的結果集 不會循覽整個table 於是那些落單的資料就永遠不會顯示了 ; 而在沒帶query的查詢 由於不會用到index 而是採用向各分散式server收集結果的方式 因此可以得到全部的資料

在網路上搜尋了一下發現不是只有我碰到這問題 在google app engine issue上有個專門的條目在講這件事
Issue 901:queries return different numbers of results in production server
看創立時間早在2008年12月就發生這issue了 這麼嚴重的問題GAE到現在還沒有解掉真的很誇張

解決方法
**目前我找到的解決方法是把消失的資料重新select出來在put()回去 就可以正常被query到**
(或許重put()時會重新依對的index排序 所以會又變正常了)
但是找出哪些資料正常哪些資料不正常實在太麻煩 所以我寫了一個把整個資料重新select出來在put()回去的程式 由於資料庫資料龐大 用最有效率的寫法也沒辦法一次做完 所以要用cron排程每分鐘做一次 一次batch 300筆出來重新put() 做完時會顯示更新了幾筆資料 像我現在資料庫裡有17191筆資料 大概會要花一小時更新完畢

程式碼如下 僅供參考
http://jkfiledownload.googlecode.com/files/GAE_scanalldata.txt
使用方法 將程式碼略做修改(將mydataDB換成你自己的資料table名) 然後放到想要的頁面handle中 設定cron去定時執行掃瞄頁面

http://yourappid.appspot.com/yourpage?action=scanalldata
=>開始掃瞄 掃瞄中會顯示目前進度 若掃瞄完畢會顯示總資料數 用cron來trigger這頁面

http://yourappid.appspot.com/yourpage?action=scanalldata&reset=true
=>不管掃瞄到一半或是掃瞄完畢都會重新掃瞄

通常重掃一次就可以解決這個問題 除非之後又有改動到index和異動了很多資料行 那就要再reset重掃一次 不過還是希望GAE能盡快解決這問題

1 意見:

張貼留言
宅之力 提到...

這問題已於2010/7/30解決
(終於)

詳情請看
http://code.google.com/p/googleappengine/issues/detail?id=2481