These are chat archives for scalikejdbc/ja

16th
Dec 2015
KAWACHI Takashi
@tkawachi
Dec 16 2015 09:06

500万行くらい入れたテーブルに

    DB.localTx { implicit session =>
      sql"SELECT id,t FROM txt".map(rs => (rs.long(1), rs.string(2))).traversable().apply()
        .foldLeft(0L) { case (a, (l, s)) => a + s.length }
    }

するといろんな例外で失敗する… なんでだろう
Mac OS X El Capitan, MySQL 5.7.10, mysql-connector-java 5.1.38, scalikejdbc 2.3.2 です

java.sql.SQLException: Unexpected exception encountered during query. とか java.lang.IllegalStateException: Transaction is not active. If you want to start a new transaction, use #newTx instead. とか java.lang.OutOfMemoryError: Java heap space とか com.mysql.jdbc.PacketTooBigException: Packet for query is too large (5789784 > 4194304). You can change this value on the server by setting the max_allowed_packet' variable. とか…
KAWACHI Takashi
@tkawachi
Dec 16 2015 10:36

http://dev.mysql.com/doc/connector-j/en/connector-j-reference-implementation-notes.html

By default, ResultSets are completely retrieved and stored in memory.

そうだったんですか…

KAWACHI Takashi
@tkawachi
Dec 16 2015 10:45
こういう感じにすればいいらしいのですが、
stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
              java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);
Kazuhiro Sera
@seratch
Dec 16 2015 13:45
session.foreach でやって mutable なコレクションに書き込むとか?
fetchsize は既に渡せますけど、それだけじゃダメなんですよね。
あとはどうしようもないなら conn を直接触ってもいいんじゃないですかねぇ。DB. localTxWithConnection とかもありますし。
KAWACHI Takashi
@tkawachi
Dec 16 2015 13:51
ドキュメントからは両方必要なように読めますが、少し試してみたら fetchsize を Integer.MIN_VALUE にするだけでも行けそうかも
KAWACHI Takashi
@tkawachi
Dec 16 2015 13:58
これは完走した
  def countWithScalikejdbcConnection(): Long = {
    DB.localTxWithConnection { connection =>

      val st = connection.prepareStatement(
        "SELECT * FROM txt" //,
      // java.sql.ResultSet.TYPE_FORWARD_ONLY,
      //java.sql.ResultSet.CONCUR_READ_ONLY
      )
      st.setFetchSize(Int.MinValue)
      val rs = st.executeQuery()
      var result = 0L
      var i = 0
      while (rs.next()) {
        result += rs.getString(2).length
        i += 1
        if (i % 1000 == 0) println(i)
      }
      result
    }
  }
これはメモリがあふれた ;(
  def countSimple(): Long = {
    DB.localTx { implicit session =>
      sql"SELECT * FROM txt"
        .map(rs => (rs.long(1), rs.string(2)))
        .traversable()
        .fetchSize(Int.MinValue)
        .apply()
        .foldLeft(0L) { case (a, (l, s)) => a + s.length }
    }
  }
大体同じことしてるつもりなんですけど、、