3

コンパイル済みの Slick クエリでコレクションをパラメーターとして使用することは可能ですか?

何かのようなもの:

private val findByIds = for {
  ids <- Parameters[Set[Int]]
  meta <- AssetMetadatas if meta.id inSet ids
} yield meta

残念ながら、上記はコンパイルされません:

scala.collection.immutable.Set[Int] を scala.collection.immutable.Set[Int] にアンパックして Any ids にパックする方法がわからない <- Parameters[Set[Int]] ^

4

2 に答える 2

9

現時点では、Slick 1 でも Slick 2 でも、inSet を使用してクエリをプリコンパイルすることはできません。さまざまな Set サイズの SQL でクエリが異なる必要があることを考えると、それは理にかなっています。

  • 0 の場合:WHERE false
  • 1:WHERE id = ?
  • 2:WHERE id IN (?,?)
  • 3 の場合:WHERE id IN (?,?,?)
  • ...

これは一般にプリコンパイルできないため、Slick は毎回 SQL をコンパイルする必要があります。ある時点で、一部のバックエンドでサポートできる可能性があります。重要な場合は、選択したセットのサイズに対していくつかのクエリを自分でプリコンパイルできます (の代わりに&&とを使用)。==inSet

inSetBind代わりに使用するinSetと、セットをリテラルとして SQL 文字列にコンパイルするのではなく、準備されたステートメントに引数として渡します。これにより、接続プールが準備済みステートメントをキャッシュできるようになります (そのように構成した場合)。したがって、Slick は引き続きクエリをコンパイルする必要がありますが、少なくともデータベースはクエリ プランをキャッシュできます。

于 2013-11-12T13:02:04.297 に答える
2

そのinSetBindためのものがあります:

private def findByIds(ids: Set[Int]) = for {
  meta <- AssetMetadatas if meta.id inSetBind ids
} yield meta

はい、これにより、 を呼び出すたびにクエリ コンパイラが呼び出さfindByIdsれますが、 の同じカーディナリティに対して常に同じ SQL が生成されますids

したがってidsSet(1,2,3)結果のSQLが生成されます。

SELECT * from AssetMetadatas WHERE ID IN (?, ?, ?)

(1, 2, 3)そして、クエリが呼び出されたときにバインドされます。呼び出すとクエリ コンパイラが再度実行されますfindByIds(Set(4,5,6))が、まったく同じ SQL が生成されます。slick がコンパイルされた AST の結果をキャッシュしないと仮定しても、データベース レベルでの節約 (バインド パラメーターを使用) と比較すると、それでもわずかなコストです。

于 2013-11-12T12:23:32.623 に答える