ruby + sqlite でinsertのベンチマークをとってみた part3
第三弾となりましたが、SQLITEのINSERTのベンチマークをとってみました。
今回はprepare。
SQLITEでは、実行時にSQL文を解析しているようですが、事前に解析を済ませてしまって、EXECUTE時の負荷を下げましょうという試みです。
条件は、
- SQL文を ? を用いた形でprepare
- SQL文を、シンボルを用いた形でprepare(with Symbol)
- 前回まであったexecute2は、prepareでは実行不可
- v2.0以降の機能であるキーワード引数(in v2.0)
- loop_countは繰り返しの回数
では早速結果を
>loop_count = 10000 user system total real standard insert 0.703000 0.015000 0.718000 ( 1.024075) st after preparing 0.266000 0.000000 0.266000 ( 0.579407) st after preparing with Symbol 0.328000 0.016000 0.344000 ( 0.657017) st after preparing with Symbol in v2.0 0.328000 0.031000 0.359000 ( 0.614970) user system total real standard insert 0.750000 0.016000 0.766000 ( 1.024316) st after preparing 0.266000 0.000000 0.266000 ( 0.593287) st after preparing with Symbol 0.343000 0.015000 0.358000 ( 0.647709) st after preparing with Symbol in v2.0 0.344000 0.000000 0.344000 ( 0.649645) >loop_count = 100000 user system total real standard insert 7.625000 0.203000 7.828000 ( 8.483301) st after preparing 2.860000 0.141000 3.001000 ( 3.389159) st after preparing with Symbol 3.593000 0.125000 3.718000 ( 4.124089) st after preparing with Symbol in v2.0 3.688000 0.094000 3.782000 ( 4.141411) user system total real standard insert 7.657000 0.203000 7.860000 ( 8.375045) st after preparing 3.000000 0.078000 3.078000 ( 3.515643) st after preparing with Symbol 3.688000 0.047000 3.735000 ( 4.125032) st after preparing with Symbol in v2.0 3.766000 0.031000 3.797000 ( 4.171897)
という結果になりました。
これを見ると、prepareでは、倍以上の速度確保出来ていることになります。
ただ、シンボルを用いるとコードは見やすくなりますが、速度が20%程度犠牲になっています。
一応コードも載せておきます。
require 'benchmark' require 'rubygems' require 'sqlite3' db = SQLite3::Database.new("Inventory.db") #使える型は、NULL、INTEGER、REAL、TEXT、BLOB db.execute(<<EOS CREATE TABLE IF NOT EXISTS Item ( ID INTEGER PRIMARY KEY AUTOINCREMENT, Code INTEGER UNIQUE NOT NULL, Name TEXT NOT NULL, Date TEXT NOT NULL ); EOS ) loop_count = 100000 insert_code = [] loop_count.times{ insert_code.push((0...20).map{ ('A'..'Z').to_a[rand(26)] }.join) } db.execute("delete from Item") Benchmark.bm(40) do |x| #standard insert with transaction x.report('standard insert'){ db.transaction loop_count.times{|i| db.execute("INSERT INTO Item (Code, Name, Date) VALUES (#{i}, '#{insert_code[i]}', '2014-08-03')") } db.commit } db.execute("DELETE FROM Item") #standard insert after preparing x.report('st after preparing'){ db.transaction pre = db.prepare("INSERT INTO Item (Code, Name, Date) VALUES (?, ?, ?)") loop_count.times{|i| pre.execute(i, insert_code[i], '2014-08-03') } db.commit } db.execute("DELETE FROM Item") #standard insert after preparing with Symbol x.report('st after preparing with Symbol'){ db.transaction pre = db.prepare("INSERT INTO Item (Code, Name, Date) VALUES (:Code, :Name, :Date)") loop_count.times{|i| pre.execute(:Code => i, :Name => insert_code[i], :Date => '2014-08-03') } db.commit } db.execute("DELETE FROM Item") #standard insert after preparing with Symbol in v2.0 x.report('st after preparing with Symbol in v2.0'){ db.transaction pre = db.prepare("INSERT INTO Item (Code, Name, Date) VALUES (:Code, :Name, :Date)") loop_count.times{|i| pre.execute(Code: i, Name: insert_code[i], Date: '2014-08-03') } db.commit } db.execute("DELETE FROM Item") end