Google App EngineでUPDATE文/DELETE文を発行するモジュールを書いた

Google App EngineのGQLはSQLライクの構文が使えますが、実際にはSQLと比べると機能がかなり制限されています。その中でも開発時に最も面倒な制限のひとつに、

一度のクエリで取得できるエンティティの数は1000個まで

という制限があります。つまり、データモデル全体に対して削除や更新をかける場合、対象となるエンティティの個数が1000を超えると一度のクエリで仕事を完了できません。何度もクエリを出しては更新・削除、というのをJavaなりPythonなりで記述して実行することになります。

オートコミットが有効な状態でSQLを1つ発行してやれば終わりのRDBMSと比べて面倒さが段違い。

あまりに面倒なので、SQLっぽいupdate文、delete文を発行し、内部でデータストアを操作モジュールを作りました。このモジュールを使うとGQLの制限下でupdate文とdelete文を発行できます。

noresult('delete from MyModel where rank < 10') # rankが10未満のエンティティをすべて削除
noresult('update MyModel set name = \'hoge\', age = 3 where age = 10') # ageが10のエンティティを更新

みたいな感じです。内部でそれぞれのupdate/delete文に対応する関数を呼んでいます。我ながらこれは便利だ・・・と思った次第。

ただ、GQLの厳しい制約により、update文の条件に不等式を使えません。GQLでは

ひとつのクエリで異なるフィールドに不等式を使えない (10 < a AND a < 20はOK, 10 < a AND b < 20はNG)
http://code.google.com/intl/ja/appengine/docs/python/datastore/queriesandindexes.html#Restrictions_on_Queries

という制約があり、update文実行の内部で、条件に合致する全エンティティにアクセスするのに不等式を使ってしまっているためです。


改善点として、更新・削除操作をトランザクションで処理できると良さそうです。
db.put/db.deleteは失敗時にロールバックしないので、中途半端に更新・削除される可能性があるので。