Почему этот простой скала-код занимает столько памяти и, наконец, вылетает? (Play Framework 2.0) - PullRequest
1 голос
/ 23 марта 2012

Я пытаюсь использовать простой код Scala в Play Framework 2.0, чтобы заполнить мою базу данных (существуют другие варианты, такие как импорт файла SQL непосредственно в базе данных, но это не главное):

def filldb = Action {
  import play.api.db.DB
  import anorm._

  var result: Boolean = false

  val tuples: List[(Long, String)] = DB
    .withConnection("playground") { implicit c =>

      for (i <- 1 until 1000000) {
        SQL("""
            INSERT INTO article (
                id,
                title
            ) VALUES (
                """ + i + """,
                'Article no """ + i + """');"""
        ).executeUpdate()

        if (i % 1000 == 0) println("i:" + i)
      }

      val sqlQuery = SQL("select id, title from article order by id;")

      sqlQuery().map(row =>
        row[Long]("id") -> row[String]("title")).toList
    }
  Ok("done")
}

В течение некоторого времени это работает хорошо (итерации по 200 КБ), замедляется, постепенно расходует память (до 1,8 ГБ) и, наконец, падает из-за нехватки памяти.

Может кто-нибудь объяснить мне, что вызывает такое поведение?Понятно, что его можно закодировать по-разному, но суть в том, чтобы понять, что не так, чтобы ошибка не возникала в другом контексте ...

Чтобы завершить, вот подробности:

  • ОС: Mac 10.6.8
  • play: 2.0
  • база данных: mysql 5.5.12
  • таблица:

    CREATE TABLE article (
    id bigint(20) NOT NULL UNIQUE,
    title varchar(255) NOT NULL,
    PRIMARY KEY (id)
    );
    

Пробовал это как weel, но безуспешно:

def filldb = Action {
  import play.api.db.DB
  import anorm._

  var result: Boolean = false
  val connection = DB.getConnection("playground")

  for (i <- 1 until 1000000) {
        SQL("""
            INSERT INTO article (
                id,
                title
            ) VALUES (
                """ + i + """,
                'Article no """ + i + """');"""
        ).executeUpdate()(connection)

        if (i % 1000 == 0) println("i:" + i)
      }

  val tuples: List[(Long, String)] = {

      val sqlQuery = SQL("select id, title from article order by id;")

      sqlQuery()(connection).map(row =>
        row[Long]("id") -> row[String]("title")).toList
    }

  connection.close()

  Ok("done")
}

Не лучше: застрял на 283k итераций ...

Ответы [ 2 ]

0 голосов
/ 12 ноября 2013

Я думаю, что ваша проблема заключается здесь:

val tuples: List[(Long, String)] = {

  val sqlQuery = SQL("select id, title from article order by id;")

  sqlQuery()(connection).map(row =>
    row[Long]("id") -> row[String]("title")).toList
}

Вы заполняете карту всеми строками в базе данных, поэтому вы заполняете структуру данных Scala / Java 1M строками.

Тебе действительно нужен миллион строк одновременно? Или они вам нужны нумерацией страниц (т. Е. Первые 20, вторые 20 и т. Д. И т. Д.).

Это не проблема воспроизведения, вы столкнетесь с той же проблемой даже при использовании java и одного простого теста jdbc. Расскажите нам реальное использование кортежей, и мы можем предоставить некоторые предложения.

0 голосов
/ 23 марта 2012

Мое первое предположение, что вы все еще можете использовать значение по умолчанию в базе данных памяти.Можете ли вы проверить и убедиться, что ваш conf / application.conf не использует jdbc: h2: mem: play?Если это так, все ваши записи будут заполнять вашу память.

Кроме того, каждое сделанное вами утверждение открывает объект оператора, который не закрывается до конца блока withConnection.Поскольку у вас в памяти миллион из них, это может накапливаться.См. http://www.playframework.org/documentation/2.0/ScalaDatabase

Вы можете попробовать заполнить БД за пределами вашей операции запроса.Я бы поэкспериментировал с 1000 партиями по 1000 и выяснил, идентифицирует ли это вашу проблему.

...