140万件程度のアクセスログを取り出して処理する際に、一旦メモリに全部咥え込むスクリプトをruby+ruby-mysqlで書いた。
アルゴリズムの是非はともかくとして、実行すると以下のようなエラーが出て止まる。
/usr/lib/ruby/gems/1.8/gems/ruby-mysql-2.9.4/lib/mysql/protocol.rb:569:in `read' : invalid packet: sequence number mismatch(19 != 254(expected)) (Mysql::Protocol Error) from /usr/lib/ruby/1.8/timeout.rb:48:in `timeout' from /usr/lib/ruby/gems/1.8/gems/ruby-mysql-2.9.4/lib/mysql/protocol.rb: 565:in `read' from /usr/lib/ruby/gems/1.8/gems/ruby-mysql-2.9.4/lib/mysql/protocol.rb: 335:in `retr_all_records' from /usr/lib/ruby/gems/1.8/gems/ruby-mysql-2.9.4/lib/mysql.rb:745:in `initialize' from /usr/lib/ruby/gems/1.8/gems/ruby-mysql-2.9.4/lib/mysql.rb:366:in `new' from /usr/lib/ruby/gems/1.8/gems/ruby-mysql-2.9.4/lib/mysql.rb:366:in `store_result' from /usr/lib/ruby/gems/1.8/gems/ruby-mysql-2.9.4/lib/mysql.rb:348:in `query' from ./db.rb:30:in `sqlToList' from analyze.rb:31 |
ググるとruby1.9でKuオプションを入れてると出てくるとか云ってるが、そもそもうちのrubyは1.8.7なので関係ないし、よく分からないエラーらしい。
ということで、最近推奨されているらしいruby-mysql2に移行することにした。
まずはgemでインストール。
gem install mysql2 |
普通に入ったので、あとはdb接続するrbファイルを修正。
require 'mysql' |
↓
require 'mysql2' |
接続初期化部分。
@db = Mysql::connect("hogehoge.jp","kaminogi","pass1234","dbname") |
↓
@db = Mysql2::Client.new(:host=> "hogehoge.jp",:username =>"kaminogi", :password=>"pass1234",:database=>"dbname") |
結果を取得してハッシュに格納する部分。
def sqlToList(sql) rows = @db.query(sql) ret = Array.new() rows.each_hash do |row| ret.push(row) end return ret end |
↓
def sqlToList(sql) rows = @db.query(sql,:cast => false) ret = Array.new() rows.each do |row| ret.push(row) end return ret end |
mysql2からは自動でキャスト機能があるらしく、datetime型の変数をdateオブジェクトに変換してくれたりするらしいが、とりあえず移行するだけならcast=falseを指定すれば動くっぽい。
同じクエリを実行したらmysql2だときちんと動いてくれた。