Ruby DBI select_all vs execute-fetch / each-finish - PullRequest
3 голосов
/ 23 января 2012

Вот мой пример кода для использования 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 ]

2 голосов
/ 29 ноября 2012

То же самое происходит, когда я запрашиваю MS SQL DB, используя DBI.connect("DBI:ODBC:Driver={SQL Server};...")

Моя работа заключалась в принудительном преобразовании DBI :: Row в массив:

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

Я поставлю 1000 долларов, что проблема связана с повторным использованием буфера - возможное повышение производительности, которое имеет нежелательные побочные эффекты!

1 голос
/ 23 января 2012

Полагаю, что 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 без блока, будет возвращен Enumerator, который в основном возвращает тот же объект db_row.

Это всего лишь предположение, но, я думаю, истина уже рядом.

UPD: исходный код здесь https://github.com/erikh/ruby-dbi/blob/master/lib/dbi/handles/statement.rb (см. Определение метода извлечения) говорит, что я ошибался, потому что @row лицензируется dup на каждую итерацию. Ну, наверное, ошибка где-то в стеке ...

...