Hatena::Grouprubyist

今日も元気にrubyist

2007-06-28

[][]rubyのベンチマーク-benchmark.rb- 20:43 rubyのベンチマーク-benchmark.rb- - 今日も元気にrubyist を含むブックマーク はてなブックマーク - rubyのベンチマーク-benchmark.rb- - 今日も元気にrubyist rubyのベンチマーク-benchmark.rb- - 今日も元気にrubyist のブックマークコメント

rubyスクリプト中の特定の処理の実行時間を知りたいと思ったことはありませんか?(ありまーす!)

ということでbenchmark.rb

no title

です。benchmark.rbを使用することで特定ブロックの実行時間を計測することができます。使い方はこんな感じ。

require 'benchmark'

Benchmark.bm do |x|
  x.report do
    10000.times do
      str = "test"
    end
  end
end

#=>
      user     system      total        real
  0.016000   0.000000   0.016000 (  0.016000)

sqlite3とArrayのパフォーマンスを比べてみる

僕はとあるアプリでsqlite3を使ってデータを保存しています。sqlの行数は200行です。しかしデータを取り出すときはsqlの全てのデータを配列に入れてから、rubyの構文を使ってデータを取り出しています。なぜなら

  • SQL文の書き方が良く分からない(SQL初心者)
  • 配列に入れたほうがピュアrubyで早くね?

からです。つまり**根拠のない理由**です。今回は僕の理由を検証するためbenchmark.rbを使ってsqlite3とArrayのパフォーマンスを計測してみることにしました。

require 'sqlite3'
require 'benchmark'

@arr_entry = Array.new
dbfile = "newsing.db"
@db = SQLite3::Database.new(dbfile)
@db.execute('select * from entry_tbl') do |row|
  @arr_entry << row
end

n = 10

# 単純実行
Benchmark.bm do |x|
  # SQL
  x.report("sql:") do
    n.times do
      @db.execute('select * from entry_tbl') do |row|
      end
    end
  end
  # 配列
  x.report("arr:") do
    n.times do
      @arr_entry.each do |elem|
      end
    end
  end
end

n = 1000

# 条件指定
Benchmark.bm do |x|
  # SQL
  x.report("sql_where:") do
    n.times do
      @db.execute(%Q[select * from entry_tbl where url = 'http']) do |row|
      end
    end
  end
  # 配列
  x.report("arr_if:") do
    n.times do
      @arr_entry.each do |elem|
        if elem[0] == "http"
        end
      end
    end
  end
end

#=>
      user     system      total        real
sql:  0.906000   0.000000   0.906000 (  0.906000)
arr:  0.000000   0.000000   0.000000 (  0.016000)
      user     system      total        real
sql_where:  0.250000   0.031000   0.281000 (  0.328000)
arr_if:  0.532000   0.000000   0.532000 (  0.531000)

単純実行の場合は配列の方が圧倒的に早かったですが、条件を指定するとSQLの方が早いです。今回は200行ですが、行数が多くなればもっと明確な差が出るかもしれません。

SQLの場合はブロックに渡す前のSQL文の実行で絞込みが終わっているのに対し、配列は取りあえず全てをブロックに渡しているからでしょう。全てに要素を取り出してif文実行すりゃ遅くなりますよね。配列もブロックに渡す前に何らかの方法で削ればいいのですが、多元配列の場合は条件指定が難しくそれこそSQL文覚えた方がよいと思います。

ということで、配列からデータを取り出している僕のアプリは見直しが必要ということが分かりました。今はアクセス数が少ないですが、将来的にはパフォーマンスを改善したいところです。