5

Tworzę nową tabelę, która musi zostać wypełniona danymi opartymi na kontach użytkowników (powyżej kilkudziesięciu tysięcy) z następującym jednorazowym zadaniem rake.Jak powinieneś wypełnić nową tabelę w Railsach?

To, co postanowiłem zrobić, to stworzyć duży łańcuch INSERT dla każdych 2000 użytkowników i wykonać to zapytanie.

Oto co kod z grubsza wygląda tak:

task :backfill_my_new_table => :environment do 
    inserts = [] 
    User.find_each do |user| 
     tuple = # form the tuple based on user and user associations like (1, 'foo', 'bar', NULL) 
     inserts << tuple 
    end 

    # At this point, the inserts array is of size at least 20,000 
    conn = ActiveRecord::Base.connection 
    inserts.each_slice(2000) do |slice| 
     sql = "INSERT INTO my_new_table (ref_id, column_a, column_b, column_c) VALUES #{inserts.join(", ")}" 
     conn.execute(sql) 
    end 
end 

Więc zastanawiam się, czy istnieje lepszy sposób to zrobić? Jakie są wady podejścia, które podjąłem? Jak mam to poprawić? Co się stanie, jeśli nie podzielę tablicy inserts i nie wykonam pojedynczego INSERT z kilkoma tysiącami krotek VALUES? Jakie są wady tej metody?

Dzięki!

+0

Dlaczego nie używałbyś metod MyNewTable zawiniętych w transakcję, aby przyspieszyć wstawianie? Obecna implementacja otwiera Cię na SQL injection. –

+0

Och, brakowało mi, że robisz wiele wkładek naraz. Byłoby to rzeczywiście szybsze (ale nie pewne, ile zawinąłeś normalne wkładki w transakcję o wartości 1000. –

Odpowiedz

0

Zależy którym PG wersji używasz, ale w większości przypadków ładowania danych luzem do stołu to wystarczy kontrolna:

  • spróbuje użyć COPY zamiast INSERT gdy jest to możliwe;
  • przypadku kilku wkładek trybu automatycznego wyłączania i owinąć każdej wkładki w jednej operacji, to jest BEGIN; INSERT ...; INSERT ...; COMMIT;
  • wyłączenie indeksów i sprawdza/ograniczenia w/tabeli docelowej;
  • wyłączenie wyzwalaczy stołu;
  • alter table więc stało unlogged (od PG 9.5, nie zapomnij włączyć zalogowaniu się po imporcie danych) lub zwiększenie max_wal_size tak WAL przyzwyczajenie być zalane

20k wierszy nie jest taka wielka sprawa dla PG, więc wstawki w plasterkach 2k w ramach jednej transakcji będą w porządku, chyba że w grę wchodzą bardzo skomplikowane bardzo skomplikowane wyzwalacze/sprawdzenia. Warto również przeczytać PG manual section on bulk loading.

UPD: a a little bit old, yet wonderful piece from depesz, fragment:

więc, jeśli chcesz wstawić dane tak szybko, jak to możliwe - stosowanie kopia (lub jeszcze lepiej - pgbulkload). jeśli z jakiegokolwiek powodu nie możesz użyć kopii, użyj wielowierszowych wstawek (nowość w wersji 8.2!). następnie, jeśli możesz, pakuj je w transakcje i wykorzystuj przygotowane transakcje, ale ogólnie - nie dają ci zbyt wiele.

Powiązane problemy