2016-01-25 12 views
24

थोक डालने का सही तरीका क्या है Slick 3.0 में अद्यतन करें?Slick 3.0 थोक डालने या अपडेट (अपरर्ट)

मैं MySQL का उपयोग कर रहा है, जहां उचित क्वेरी होगा

INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6) 
ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b); 

MySQL bulk INSERT or UPDATE

यहाँ मेरे वर्तमान कोड है जो बहुत ही धीमी गति :-(

// 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 

मैं क्या देख रहा हूँ है

def insertOrUpdate(values: Iterable[U]): DriverAction[MultiInsertResult, NoStream, Effect.Write] 
के बराबर है

उत्तर

28

ऐसे कई तरीके है कि आप इस कोड तेजी से (हर एक चाहिए बना सकते हैं पूर्ववर्ती लोगों की तुलना में तेजी हो, लेकिन यह उत्तरोत्तर कम मुहावरेदार-चालाक हो जाता है):

  • सभी को एक बार अपने DBIO घटनाओं भागो, बल्कि करने के लिए हर एक के लिए इंतजार कर से इससे पहले कि आप अगले चलाने के लिए प्रतिबद्ध:

    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 
    
  • ड्रॉप JDBC स्तर तक नीचे और एक ही बार में सभी अपने Upsert चलाने (idea via this answer):

    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

कूल है तो मेरे मामले में एक अखंडता अपवाद फेंक देगा। विशेष रूप से दूसरी तकनीक के लिए धन्यवाद। मुझे उस – user1902291

+0

के बारे में पता नहीं था बस डबल चेक करने के लिए: पहला समाधान बैच में सम्मिलित नहीं है, है ना? ऐसा लगता है कि यह समानांतर बॉट में सभी आवेषण नहीं कर रहा है, है ना? – ignasi35

+0

सही @ ignasi35 –

0

जैसा कि आप Slick examples पर देख सकते हैं, आप जेडीबीसी बैच सम्मिलित सुविधा का उपयोग करके ++= फ़ंक्शन का उपयोग कर सकते हैं। प्रति उदाहरण:

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

भी कर सकते हैं "आकार" द्वारा "समूहीकरण" पंक्तियों अनुक्रम आप बैच:

val batchSize = 1000 
rows.grouped(batchSize).foreach { group => foos ++= group } 
+9

धन्यवाद नहीं है, लेकिन मैं ऐसा नहीं लगता ++ = insertOrUpdate करता है। मेरा मानना ​​है कि यह सिर्फ सम्मिलित है, और यदि मेरे पास एक डुप्लिकेट पंक्ति – user1902291

0

उपयोग sqlu

इस डेमो काम

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) 
    } 
    }) 
} 

और मैं एक एकल एसक्यूएल में sqlu इस्तेमाल करने की कोशिश, लेकिन त्रुटि हो सकता है न sqlu आपूर्ति स्ट्रिंग अंतर्वेशन

इस डेमो काम

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) 
    } 
    }) 
} 

के साथ एक mysql समन्वयन टूल स्केला चालाक https://github.com/cclient/ScalaMysqlSync

संबंधित मुद्दे