[Scala][Slick] Slickはあまり実用的な選択肢ではない

 SlickはScalaのORMです。Scalaの基本的なデータ構造であるリストとタプルにマッピングし、Scalaのリスト操作を用いてDBを操作することができる非常に便利なORMです。私もしばらくこのSlickを触って来ましたが、やはり発展途上というか、現時点ではORMとして使うには少し難がありました。今回はその点についてまとめたいと思います。

結合の問題

 細かな問題は様々ありますが、大きな問題はこの結合です。

 Slickでは、リスト操作を用いてクエリを生成することが可能です。

val q = for {
  u <- User
  a <- Article if u.id === a.writer_id
} yield (u.email, u.name, a.title)

 こんな感じですね。

 この文によって生成されるクエリとして期待されるのは、以下のとおりです。

SELECT
    u.email, u.name, a.title
FROM User AS u
INNER JOIN Article AS a
    ON u.id = a.writer_id

 User.idとArticle.writer_idで内部結合した結果を取得する普通のクエリです。しかし、Slickでは以下の様なクエリが生成されます(下記のクエリは読みやすく書き換えたものです。実際には連番等が多用された読みにくいクエリが生成されます)。

SELECT
    u.email, u.name, a.title
FROM (
    SELECT v.id, v.email, v.name FROM User AS v
) u
INNER JOIN (
   SELECT b.writer_id, b.title FROM Article AS b
) a
ON u.id = a.writer_id

 本来テーブル名が記述されるべき部分にサブクエリが記述されています。このサブクエリは、あるテーブルのすべての要素を取得するため、どこにインデックスを貼ろうともインデックスが適用されることはありません。

 なぜこのようなクエリが出力されるのかというと、for式(シーケンス内包記法)を用いて部分的なクエリから順番に生成しているからだと考えられます。データ数が少なければ問題ないかもしれませんが、データ数が増える、或いは結合するテーブル数が増えると爆発的に遅くなります。
 RDBのORMなのに実質Joinが使えないことになるので、現状ではORMとしてSlickを選択するのはあまり実用的ではないと思います。もちろん、Slickは素のクエリを記述することができ、JDBCのプレースホルダっぽいものや、補間子(interpolation)を用いたクエリ生成が可能なので、Scalaのリスト操作のような記述を用いないORMとしては十分便利に使えそうです。

 だいぶ調査不足なので間違ってるかもしれません。詳しいことは

https://groups.google.com/forum/#!topicsearchin/scalaquery/authorname$3ADenis/scalaquery/EXihfXbHmSI

 上記のスレッドに記載されています。

0 件のコメント :

コメントを投稿