Berufung auf eine große Gruppe von SQL aus einer Rails-Anwendung 4
Ich habe eine Rails-Anwendung 4, die ich benutze, in Verbindung mit sidekiq
zum ausführen von asynchronen jobs. Einer der jobs, die ich normalerweise laufen außerhalb meiner Rails-Anwendung ist eine große Anzahl von komplexen SQL-Abfragen, die nicht wirklich modelliert werden durch ActiveRecord. Die Verbindung dieser Satz von SQL-Abfragen hat mit meiner Rails-app ist, dass es ausgeführt werden soll, jederzeit einen meiner controller-Aktionen aufgerufen.
Ideal, ich würde Warteschlange ein Auftrag von meiner Rails Applikation im controller für Sidekiq zu gehen und die Abfragen ausführen. Jetzt sind Sie gespeichert, in eine externe Datei aus, und ich bin mir nicht ganz sicher, was der beste Weg ist, zu haben Schienen laufen die besagten SQL.
Alle Lösungen werden geschätzt.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich Stimme mit Sharagoz, wenn Sie muss nur noch eine spezielle Abfrage, der beste Weg ist, zum senden der Abfrage-string direkt in die Verbindung, wie:
Wenn die Abfrage nicht statisch, und Sie haben, um es zu verfassen, würde ich Arel, es ist bereits in Rails 4.x:
ActiveRecord::Base.connection.execute
wird nicht ausgeführt, mehrere SQL-Anweisungen gleichzeitigIhnen nicht sagen, welche Datenbank Sie verwenden, so gehe ich davon aus MySQL.
Könnten Sie berappen, um die
mysql
binäre die Arbeit machen:Oder verwenden Sie
ActiveRecord::Base.connection.execute(File.read("huge.sql"))
, aber es wird nicht funktionieren, out of the box wenn Sie mehrere SQL-Anweisungen in der SQL-Datei.In Reihenfolge für die Ausführung mehrerer Anweisungen, die Sie benötigen, um erstellen Sie einen Initialisierer, dass monkey patches die
ActiveRecord::Base.mysql2_connection
zu ermöglichen die Einstellung von MySQL ist CLIENT_MULTI_STATEMENTS und CLIENT_MULTI_RESULTS flags.Erstellen Sie eine neue Initialisierung
config/initializers/mysql2.rb
Dann update
config/database.yml
hinzufügen flags:Ich gerade getestet on Rails 4.1 und es funktioniert Super.
Quelle: http://www.spectator.in/2011/03/12/rails2-mysql2-and-stored-procedures/
Ausführen einer Abfrage ist - wie von anderen Menschen - ganz einfach durch
Du redest von einem 20.000 sql Skript mehrere Abfragen. Vorausgesetzt, Sie haben die Datei etwas unter Kontrolle haben, können Sie extrahieren Sie die einzelnen Abfragen aus.
Wenn man Glück hat, kommt dann die Abfrage Trennzeichen kann ";\n\n", aber das kommt natürlich auf dein script. Wir hatten in einem anderen Beispiel "\x0" als Trennzeichen. Der Punkt ist, dass Sie teilen Sie das Skript in Abfragen, um Sie in die Datenbank. Ich wickelte es in eine Transaktion zu ermöglichen, damit die Datenbank weiß, dass es kommen mehr als eine Anweisung. Die Sperrung verpflichtet, wenn keine Ausnahme ausgelöst wird, während das senden der script-Abfragen.
Wenn Sie nicht die Skript-Datei unter Kontrolle, beginnen Sie zu reden, um diejenigen, die es kontrollieren, erhalten Sie eine zuverlässige Trennzeichen. Wenn es nicht unter Ihrer Kontrolle, und Sie kann nicht sprechen, zu dem, der ihn kontrolliert, würden Sie nicht ausführen, ich denke
:-)
.UPDATE
Dies ist eine Allgemeine Möglichkeit, um dieses Problem zu lösen. Für PostgreSQL, die Sie nicht brauchen, um teilen Sie die Anweisungen manuell. Sie können nur senden Sie Sie alle auf einmal über
execute
. Für MySQL ist, scheint es Lösungen, um die adapter in eine CLIENT_MULTI_STATEMENTS - Modus.Wenn Sie ausführen möchten, raw-SQL über active record Sie können diese API verwenden:
ActiveRecord::Base.connection.execute("SELECT COUNT(*) FROM users")
ActiveRecord::Base.connection.execute
wird nicht ausgeführt, mehrere SQL-Anweisungen auf einmal.execute
unterstützt mehrere statements für PostgreSQL. Für MySQL gibt es einen Weg, es zu erreichen (wie @infundiert zeigte).Wenn Sie mit großen SQL-jedes mal, schlage ich vor, Sie erstellen eine sql
view
für Sie. Es werden steigern die Ausführungszeit. Die andere Sache ist die, wenn möglich, versuchen, teilen alle diese SQL-Abfrage in einer solchen Weise, dass es ausgeführt werden, parallel statt sequenziell und dann schieben Sie es aufsidekiq
Warteschlange.Verwenden Sie
ActiveRecord::Base.connection.execute
oderModelClass.find_by_sql
zum ausführen von benutzerdefinierten SQL.Auch, ein Auge auf
ROLLBACK
Transaktionen, finden Sie viele Orte, wo Sie nicht brauchen, solcheROLLBACK
Funktion. Wenn Sie vermeiden, dass die Abfrage schneller ausgeführt werden, aber es ist gefährlich.Dank alle, die ich vorschlagen kann.
ActiveRecord::Base.connection.execute
undModelClass.find_by_sql
zum Beispiel)- es könnte sehr gut geschnitten deutlich gesenkt Abfrage Vorbereitung Zeit in die DB und Ihr code leichter zu handhabenNehme ich an, dass Sie MySQL verwenden, aber Ihre Laufleistung variieren je nach DB-Typ, den Sie verwenden. Zum Beispiel hat Oracle einige gute Edelsteine für die Handhabung von gespeicherten Prozeduren, Ansichten etc, zum Beispiel https://github.com/rsim/ruby-plsql
Lassen Sie mich wissen, wenn einige dieser Dinge nicht passen, Ihren Fall und ich werde zu erweitern
Ich sehe dieser Beitrag ist sowas von alt. Aber ich möchte hinzufügen, meine Lösung dafür. Ich war in einer ähnlichen situation; ich musste auch einen Weg, um force feed "PRAGMA foreign_keys = on;" in meiner sqlite-Verbindung (konnte ich nicht finden einem früheren post geschrieben, dass es aus wie es zu tun.) Anywho, das arbeitete wie ein Charme für mich. Es erlaubt mir zu schreiben, "ziemlich" sql und noch bekommen, ausgeführt. Leere Zeilen werden ignoriert, indem Sie die if-Anweisung.
Ich hatte das gleiche problem mit einer Reihe von sql-Anweisungen, die ich brauchte, um ausführen alle in einem Aufruf an den server. Was für mich gearbeitet wurde die Einrichtung einer Initialisierung für Mysql2-adapter (wie beschrieben in der infundiert Antwort), aber auch einige zusätzliche Arbeit, um die Verarbeitung mehrerer Ergebnisse. Ein direkter Aufruf zu
ActiveRecord::Base.connection.execute
würde nur abrufen, das erste Ergebnis und das Problem ist ein Interner Fehler.Meine Lösung war, um Mysql2-adapter und direkt mit ihm:
Dann, wie bereits erläutert,hier, die Abfrage ausführen und in einer Schleife durch die Ergebnisse: