2012-06-26 2 views
4

У меня проблема, когда я обновляю миллионы строк в моей базе данных, поэтому вместо того, чтобы обновлять каждую из них отдельно, я хочу объединить группы из 1000 операторов в один запрос.Ruby mysql2 несколько операторов в одном запросе

Я включил MULTI_STATEMENTS как так

client = Mysql2::Client.new(:host => 'localhost', :database => 'mehdb', :username => "root", :password => "", :flags => Mysql2::Client::MULTI_STATEMENTS) 

Вот пример кода, который я бегу

sql = "SELECT id, x FROM pew WHERE x IS NULL LIMIT 1000" 

results = db_read.query(sql) 

while results.count > 0 

    updates = '' 

    results.each do |r| 
    updates += "UPDATE pew SET x = 10 WHERE id = #{r['id']};" 
    end 

    db_write.query(updates) unless updates.empty? 

    results = db_read.query(sql) 
end 

Эта работа в порядке во время первого запуска через, но затем, когда он выстреливает второй набор обновлений Я получаю это сообщение об ошибке

`query': Commands out of sync; you can't run this command now (Mysql2::Error) 

С кем это может быть передние? Или какие-либо рекомендации по другому подходу?

ответ

7

Короткий ответ к этой проблеме, когда MULTI_STATEMENTS включена MySQL ожидает обрабатывать результат Ваш запрос.

Быстрое исправление сделать что-то похожее на это после каждого набора нескольких операторов обновления

while db_write.next_result 
    db_write.store_result rescue '' 
    end 
+0

Примечание: 'db_write' есть' ActiveRecord :: Base.connection.raw_connection' – Envek

1

Почему вы не только ::

Нет необходимости запускать его несколько раз ....

UPDATE pew SET x = 10 WHERE x IS NULL 
+0

«х = 10» является всего лишь пример, который я поставил здесь, в моем фактическом коде im, устанавливая это для чего-то другого для каждой строки. – Marklar

+0

делает ли значение для установки в таблице из другой таблицы? –

+0

Его вычислили несколько других столбцов в нескольких других таблицах. Я мог бы написать функцию mysql, чтобы сделать это, но я надеюсь получить решение для этого в Ruby, так как это облегчает мою жизнь, если я могу использовать несколько существующих rubygems, чтобы выполнить большую часть работы для меня. – Marklar

1

Как я понимаю, это результат Mysql внутренняя защита - Вы среди запросов БД, и потоковой передачи результатов, если во время этого вы также обновите результаты, вы не можете гарантировать какой-либо уровень согласованности.

Если вы знаете, что вы в безопасности, чтобы внести изменения в качестве части потока, вы могли бы работать вокруг этого, просто создавая второе соединение:

reading_client = Mysql2::Client.new(:host => 'localhost', :database => 'mehdb', :username => "root", :password => "", :flags => Mysql2::Client::MULTI_STATEMENTS) 

updating_client = Mysql2::Client.new(:host => 'localhost', :database => 'mehdb', :username => "root", :password => "", :flags => Mysql2::Client::MULTI_STATEMENTS) 


sql = "SELECT id, x FROM pew WHERE x IS NULL LIMIT 1000" 

results = reading_client.query(sql) 

while results.count > 0 

    updates = '' 

    results.each do |r| 
    updates += "UPDATE pew SET x = 10 WHERE id = #{r['id']};" 
    end 

    updating_client.query(updates) unless updates.empty? 

    results = reading_client.query(sql) 
end