Ich habe eine Funktion zum Ausgeben von Protokollinformationen aus der Datenbank erstellt, da ich Protokollinformationen vom Client analysieren möchte.
Aufgrund der Ausgabe des Protokolls nach dem Start des eigentlichen Vorgangs dauerte die Ausgabe des CSV lange, wenn das Protokoll etwa 1 oder 2 Tage alt war. Es dauert jedoch zu lange, bis der gesamte Zeitraum nützlich ist. Ich bin in eine solche Situation geraten. Als ich es tatsächlich ausprobierte, wurde es auch nach 15 Minuten nicht ausgegeben und befand sich im Status "Ich kann dies nicht sicher verwenden ...". Daher habe ich versucht, das Protokoll auszugeben, indem ich direkt auf SQL geklickt habe.
[Lassen Sie uns DB-Daten im CSV-Format mit Rails | ausgeben
Ich habe die allgemeine CSV-Ausgabe mit der CSV-Bibliothek wie folgt ausgegeben. (Ist das das?
library csv (Ruby 2.7.0 Referenzhandbuch)
)
Dieses Mal verwende ich die CSV-Bibliothek, um Abfragen mit unformatierten SQL- und Ausgabeprotokollen auszugeben, aber die Verwendung unterscheidet sich geringfügig.
Die Methode to_sql
wird verwendet, um das von ActiveRecord ausgegebene SQL in Raw-SQL zu konvertieren und auszugeben.
app/services/large_csv_exporter_service.rb
class LargeCsvExporterService
require 'csv'
attr_accessor :table, :column, :host, :username, :password, :database
def initialize(table, column, host, username, password, database)
@table = table
@column = column
@host = host
@username = username
@password = password
@database = database
end
def set_file_name(file_name)
@csv_file_name = file_name
end
def set_query(query)
results = @client.query(query)
results
end
def write_csv(results)
# File.write(@csv_file_name, encoding: Encoding::SJIS) unless File.exist? @csv_file_name
CSV.open("./tmp/csv_export/#{@csv_file_name}", "w:sjis") do |csv|
csv << results.fields
results.each do |row|
csv << row.values
end
end
end
def export_csv_file
filepath = "./tmp/csv_export/#{@csv_file_name}"
stat = File::stat(filepath)
return filepath, stat, @csv_file_name
end
def delete_created_csv_file
if File.exist?("./tmp/csv_export/#{@csv_file_name}")
File.delete("./tmp/csv_export/#{@csv_file_name}")
end
end
def set_client
# cache_rows:Falsch, um die Verwendung von Speicher zu vermeiden
@client = Mysql2::Client.new(
host: host,
username: username,
password: password,
database: database,
stream: true,
cache_rows: false,
)
end
end
Ich verwende den Dienst in einem Controller. Von der Mitte "csv_export = LargeCsvExporterService.new (" access_logs "," * ", ENV [" DB_D_HOST "], ENV [" DB_D_USERNAME "]," ", ENV [" DB_D_NAME "]) "ENV [" DB_D_HOST "]" bezieht sich auf den DB-Namen oder Benutzernamen von .env (dotenv).
Ich kann keinen hübschen Code schreiben, also schauen Sie bitte genau hin.
app/controllers/admins/access_logs_controller.rb
def export_csv(params_q)
@q = AccessLog.order(id: :asc).ransack(params_q)
user_type_param = params[:q][:user_type].empty? ? ["user", "admin", "supplier"] : params[:q][:user_type].split(':')[1]
methoda_type_param = params[:q][:method_type] == "ALL_TYPE" ? AccessLog.distinct.pluck(:method_type).compact : params[:q][:method_type]
access_dates = AccessLog.order(access_date: :asc).to_a
from_time = params[:q][:created_at_gteq].empty? ? access_dates.first.access_date : params[:q][:created_at_gteq].to_time
to_time = params[:q][:created_at_lt].empty? ? access_dates.last.access_date : params[:q][:created_at_lt].to_time
sql_query = AccessLog.where(user_type: user_type_param).where(method_type: methoda_type_param).where(created_at: [from_time..to_time]).to_sql
csv_export = LargeCsvExporterService.new("access_logs", "*", ENV["DB_D_HOST"], ENV["DB_D_USERNAME"], "", ENV["DB_D_NAME"])
csv_export.set_file_name("AccessLog_#{Time.zone.now.strftime("%Y%m%d%S")}.csv")
csv_export.set_client
# results = csv_export.set_query("SELECT * FROM access_logs WHERE created_at BETWEEN '#{from_time}' AND '#{to_time}' AND method_type = '#{methoda_type_param}' AND user_type = '#{user_type_param}'" )
results = csv_export.set_query(sql_query)
csv_export.write_csv(results)
filepath, stat, csv_file_name = csv_export.export_csv_file
send_result = send_file(filepath, :filename => csv_file_name, :length => stat.size)
# csv_export.delete_created_csv_file
end
Die SQL-Abfrage gibt so etwas in einer Zeile aus
SELECT `access_logs`.*
FROM `access_logs`
WHERE `access_logs`.`user_type` = 'user'
AND `access_logs`.`method_type` IN ( 'GET', 'POST' )
AND `access_logs`.`created_at` BETWEEN
'2020-08-25 00:00:00' AND '2020-09-27 23:55:35'
Nun, so habe ich die Zeit nicht wirklich gemessen, aber jetzt kann ich ungefähr 100.000 Dateien in ungefähr 10 Sekunden ausgeben.
Recommended Posts