2014年01月11日

Slickのelementsメソッドがfetchすることを確認する

Slickで取ったSQLの結果はたいていlistかfirstOptionで取っていたのだけど、大きめの結果を取る場合はfetchした方が良いよなという事で、elementsを使ってみる。

確認のため、1000万件の結果を取得させてみて、listと比べてメモリ消費量が少ないことを確認する。

とりあえずテーブル作成。

import scala.slick.driver.H2Driver.simple._

case class Coffee(id: Int, name: String, price: Int, size: String, sugar: Boolean)

object Coffees extends Table[Coffee]("coffees") {
  def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
  def name = column[String]("name", O.NotNull)
  def price = column[Int]("price", O.NotNull)
  def size = column[String]("size", O.NotNull)
  def suger = column[Boolean]("sugar", O.Default(true))

  def * = id ~ name ~ price ~ size ~ sugar <> (Coffee, Coffee.unapply _)
}
1000万件データを入れる。
  val url = "jdbc:h2:test1"
  Database.forURL(url, driver = "org.h2.Driver") withSession { implicit session: Session =>
    Coffees.ddl.create
    val rand = new Random()
    val size = Array("L", "S", "M")
    for (i <- 0 to 10000000) {
      Coffees.insert(Coffee(i, "適当", rand.nextInt(1000), size(rand.nextInt(3)), true))
    }
  }

全件取ってきて、priceのMAXを取るという無駄な処理を書く。listではなくelementsで取る。2ヶ所で簡単なメモリ量計測を入れる。

  val url = "jdbc:h2:test1"
  Database.forURL(url, driver = "org.h2.Driver") withSession { implicit session: Session =>
    def mem() = (Runtime.getRuntime.totalMemory - Runtime.getRuntime.freeMemory) / 1024 / 1024 
    val startMem = mem()
    val ite = Query(Coffees).elements
    println(mem() - startMem)
    try ite.foldLeft(0) { (i, c) => c.price.max(i) }
    finally ite.close()
    println(mem() - startMem)
  }

この時、メモリの使用料はどちらも158MB→230MB。意外と使いますね。

次にlistで取った場合。コードの差で違いが出ないように、ほぼ同じようにコードにする。

  val url = "jdbc:h2:test1"
  Database.forURL(url, driver = "org.h2.Driver") withSession { implicit session: Session =>
    def mem() = (Runtime.getRuntime.totalMemory - Runtime.getRuntime.freeMemory) / 1024 / 1024 
    val startMem = mem()
    val ite = Query(Coffees).list.iterator
    println(mem() - startMem)
    try ite.foldLeft(0) { (i, c) => c.price.max(i) }
    //finally ite.close()
    println(mem() - startMem)
  }

この時、メモリの使用量は1084MB→1239MB。

1239MB → 230MBということで、ちゃんと仕事はしてくれているようだ。