Ruby DBI select_all vs execute-fetch / each-finish

时间:2012-01-23 13:28:58

标签: ruby dbi

以下是我使用DBI的示例代码:

dbh = DBI.connect("DBI:Mysql:host=#{server};database=mysql", user, pass)
rows = dbh.select_all("SHOW TABLES")

这里的行打印如下:

[["user"], ["user"], ["user"], ["user"], ["user"], ["user"], ["user"], ["user"],
 ["user"], ["user"], ["user"], ["user"], ["user"], ["user"], ["user"], ["user"],
 ["user"]]

这是打印mysql数据库中的最后一个表,但记录总数是正确的。

如果我使用execute-fetch / each-finish序列执行此操作,如下所示:

sth = dbh.execute("SHOW TABLES")
sth.each do |row|
  rows << row[0]
end
sth.finish

但它给了我正确的结果,如:

["columns_priv", "db", "func", "help_category", "help_keyword", "help_relation",
 "help_topic", "host", "proc", "procs_priv", "tables_priv", "time_zone", "time_z
one_leap_second", "time_zone_name", "time_zone_transition", "time_zone_transitio
n_type", "user"]

帮我解决这个问题?

2 个答案:

答案 0 :(得分:2)

使用DBI.connect("DBI:ODBC:Driver={SQL Server};...")

查询MS SQL DB时也会发生同样的情况

我的工作是强制将DBI :: Row转换为数组:

sth = dbh.execute "..."
begin
  return sth.map{ |row| row.to_a }
ensure
  sth.finish
end

我敢打赌1000美元的问题与缓冲区重用有关 - 一种可能的“性能”增强,它具有不可抗拒的副作用!

答案 1 :(得分:1)

我猜dbh.select_all返回一个Enumerator实例,它在每次迭代时产生相同的行。看到这个伪代码来理解我的意思:

def select_all(query)
  db_row = Row.new
  reader = @connection.execute_reader(query)
  Enumerator.new do |yielder|
    until reader.end?
      db_row.populate_from(reader)
      yielder.yield db_row
      reader.next!
    end
  end
end

因此,如果你在没有块的情况下使用select_all,将返回一个枚举器,它基本上产生相同的db_row对象。

这只是猜测,但我相信事实就在附近。

UPD:这里的源代码https://github.com/erikh/ruby-dbi/blob/master/lib/dbi/handles/statement.rb(请参阅获取方法定义)说我错了,因为@row在每次迭代时都是dup。好吧,可能错误就在堆栈的某个地方......