2016-01-25 41 views
24

Toplu bir eklenti yapmak için doğru yol nedir?Slick 3.0 toplu ekleme veya güncelleştirme (yükseltme)

ben uygun sorgu nerede olacağını MySQL kullanıyorum İşte

MySQL bulk INSERT or UPDATE

INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6) 
ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b); 
ı Aradıklarım çok yavaş :-(

// FIXME -- this is slow but will stop repeats, an insertOrUpdate 
// functions for a list would be much better 
val rowsInserted = rows.map { 
    row => await(run(TableQuery[FooTable].insertOrUpdate(row))) 
}.sum 

benim şimdiki kodudur

def insertOrUpdate(values: Iterable[U]): DriverAction[MultiInsertResult, NoStream, Effect.Write] 
'in karşılığıdır.

cevap

28

) Yukarıdaki olanlardan daha hızlı olabilir ama giderek daha az deyimsel-kaygan alır:

  • yerine her biri için beklemek yerine, tek seferde DBIO olayları Run (idea via this answer) aşağı JDBC seviyesine

    val toBeInserted = rows.map { row => TableQuery[FooTable].insertOrUpdate(row) } 
    val inOneGo = DBIO.sequence(toBeInserted) 
    val dbioFuture = run(inOneGo) 
    // Optionally, you can add a `.transactionally` 
    // and/or `.withPinnedSession` here to pin all of these upserts 
    // to the same transaction/connection 
    // which *may* get you a little more speed: 
    // val dbioFuture = run(inOneGo.transactionally) 
    val rowsInserted = await(dbioFuture).sum 
    
  • Drop ve tek seferde tüm Upsert çalıştırın:: Bir sonraki çalıştırmadan önce taahhüt

    val SQL = """INSERT INTO table (a,b,c) VALUES (?, ?, ?) 
    ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);""" 
    
    SimpleDBIO[List[Int]] { session => 
        val statement = session.connection.prepareStatement(SQL) 
        rows.map { row => 
        statement.setInt(1, row.a) 
        statement.setInt(2, row.b) 
        statement.setInt(3, row.c) 
        statement.addBatch() 
        } 
        statement.executeBatch() 
    } 
    
+0

Cool varsa bir bütünlük istisnası atacaktır. Özellikle ikinci teknik için teşekkür ederim. Ben bu konuda bilmiyordum – user1902291

+0

Sadece doublecheck: ilk çözüm toplu olarak ekleyerek değil, değil mi? Paralel botta tüm ekleri toplu halde yapmıyor gibi görünüyor, değil mi? – ignasi35

+0

Doğru @ ignasi35 –

0

Slick examples'da gördüğünüz gibi, JDBC toplu iş özelliği özelliğini kullanarak eklemek için ++= işlevini kullanabilirsiniz. Mesela başına:

val foos = TableQuery[FooTable] 
val rows: Seq[Foo] = ... 
foos ++= rows // here slick will use batch insert 

yapabilirsiniz ayrıca "boyutu" "gruplama" satırları dizisi ile size toplu:

(her biri gerektiği daha hızlı bu kodu kazanmanın çeşitli yolları vardır
val batchSize = 1000 
rows.grouped(batchSize).foreach { group => foos ++= group } 
+9

Teşekkür dont'iş ama sqlu düşünmeyin ++ = insertOrUpdate. Yalnızca eklendiğine inanıyorum ve benim durumumda yinelenen satır – user1902291

0

kullanımı sqlu

bu demo çalışması

case ("insertOnDuplicateKey",answers:List[Answer])=>{ 
    def buildInsert(r: Answer): DBIO[Int] = 
    sqlu"insert into answer (aid,bid,sbid,qid,ups,author,uid,nick,pub_time,content,good,hot,id,reply,pic,spider_time) values (${r.aid},${r.bid},${r.sbid},${r.qid},${r.ups},${r.author},${r.uid},${r.nick},${r.pub_time},${r.content},${r.good},${r.hot},${r.id},${r.reply},${r.pic},${r.spider_time}) ON DUPLICATE KEY UPDATE `aid`=values(aid),`bid`=values(bid),`sbid`=values(sbid),`qid`=values(qid),`ups`=values(ups),`author`=values(author),`uid`=values(uid),`nick`=values(nick),`pub_time`=values(pub_time),`content`=values(content),`good`=values(good),`hot`=values(hot),`id`=values(id),`reply`=values(reply),`pic`=values(pic),`spider_time`=values(spider_time)" 
    val inserts: Seq[DBIO[Int]] = answers.map(buildInsert) 
    val combined: DBIO[Seq[Int]] = DBIO.sequence(inserts) 
    DEST_DB.run(combined).onComplete(data=>{ 
    println("insertOnDuplicateKey data result",data.get.mkString) 
    if (data.isSuccess){ 
     println(data.get) 
     val lastid=answers.last.id 
     Sync.lastActor !("upsert",tablename,lastid) 
    }else{ 
     //retry 
     self !("insertOnDuplicateKey",answers) 
    } 
    }) 
} 

ve ben tek sql sqlu kullanmayı deneyin ama hata belki

bu demo tedarik Dize interpolasyon yok

case ("insertOnDuplicateKeyError",answers:List[Answer])=>{ 
    def buildSql(execpre:String,values: String,execafter:String): DBIO[Int] = sqlu"$execpre $values $execafter" 
    val execpre="insert into answer (aid,bid,sbid,qid,ups,author,uid,nick,pub_time,content,good,hot,id,reply,pic,spider_time) values " 
    val execafter=" ON DUPLICATE KEY UPDATE `aid`=values(aid),`bid`=values(bid),`sbid`=values(sbid),`qid`=values(qid),`ups`=values(ups),`author`=values(author),`uid`=values(uid),`nick`=values(nick),`pub_time`=values(pub_time),`content`=values(content),`good`=values(good),`hot`=values(hot),`id`=values(id),`reply`=values(reply),`pic`=values(pic),`spider_time`=values(spider_time)" 
    val valuesstr=answers.map(row=>("("+List(row.aid,row.bid,row.sbid,row.qid,row.ups,"'"+row.author+"'","'"+row.uid+"'","'"+row.nick+"'","'"+row.pub_time+"'","'"+row.content+"'",row.good,row.hot,row.id,row.reply,row.pic,"'"+row.spider_time+"'").mkString(",")+")")).mkString(",\n") 
    val insertOrUpdateAction=DBIO.seq(
    buildSql(execpre,valuesstr,execafter) 
) 
    DEST_DB.run(insertOrUpdateAction).onComplete(data=>{ 
    if (data.isSuccess){ 
     println("insertOnDuplicateKey data result",data) 
     //retry 
     val lastid=answers.last.id 
     Sync.lastActor !("upsert",tablename,lastid) 
    }else{ 
     self !("insertOnDuplicateKey2",answers) 
    } 
    }) 
} 

ile mysql senkronizasyon aracı scala kaygan https://github.com/cclient/ScalaMysqlSync