2016-05-03 3 views
1

У меня есть две таблицы users и notes с более чем 50 тыс. Записей в пользователях и 90 тыс. Записей в заметках.Как эффективно получить все строки из огромной таблицы в Rails?

class User < ActiveRecord::Base 
    has_many :notes 
end 

Схема users_table:

id email created_at 

Схема notes_table:

id user_id created_at category impact_score 

Я пытаюсь создать временную таблицу temp_user_notes, которая может иметь данные обеих таблиц, на которых я могу выполнить запросы ActiveRecord для извлечения данных.

Схема user_notes_table:

id user_id notes_id email user_created_at notes_created_at category impact_score 

Я делаю это

def self.populate_temp_user_notes 
    users = User.all 
    users.each do |user| 
     user.notes.each do |note| 
     user_notes = TempUserNote.new 
     user_notes.user_id = user.id 
     user_notes.notes_id = note.id 
     user_notes.auth_token_created_at = user.auth_token_created_at 
     user_notes.notes_recorded_at = note.recorded_at 
     user_notes.category = note.category 
     user_notes.well_being_score = note.perception_score 
     user_notes.save 
     end 
    end 
    end 

Перебор всех видов использования и их нот процесса, что другой подход может я использовать пищу очень долгую память?

EDIT Отсюда: -

Моего требование: У меня есть ряд запросов, разделенных AND и OR условия, которые принимают использование выполнено из следующей таблицы: пользователи, заметки, транзакция подписка. предположим, что мой запрос для получения целевых пользователей - (Query1 OR Query2) AND Query3 AND Query4 , тогда вывод каждого запроса вводится следующим запросом.

например:

total users in DB = 1000 
1. user_list = (Query1 or Query2) #=> 500 users 
2. taking 500 users from user_list as input for next query 
3. user_list = user_list AND Query3 #=> 300 users 
4. taking 300 users from point 3 as input for query in point 4 
5. user_list = user_list AND Query4 #=> 50 users 

в последнем списке пользователей у меня есть мои целевые пользователи и там отмечается.

ответ

3

Я хотел бы использовать комбинацию find_each и includes уменьшить как: использование памяти и количество запросов к базе данных:

def self.populate_temp_user_notes 
    User.includes(:notes).find_each do |user| 
    user.notes.each do |note| 
     TempUserNote.create(
     user_id:    user.id, 
     notes_id:    note.id, 
     auth_token_created_at: user.auth_token_created_at, 
     notes_recorded_at:  note.recorded_at, 
     category:    note.category, 
     well_being_score:  note.perception_score, 
    ) 
    end 
    end 
end 

Другой очень быстрый вариант может быть сделать это с простым SQL, как это:

INSERT INTO temp_user_notes 
    (user_id, notes_id, auth_token_created_at, notes_recorded_at, category, well_being_score) 
    SELECT users.id, notes.id, users.auth_token_created_at, notes.recorded_at, notes.category, notes.perception_score 
    FROM users INNER JOIN notes ON users.id = notes.user_id; 
0

С огромным количеством данных было бы полезно использовать User.all. Представьте, что вы извлекаете 50 тыс. Строк данных, а затем для каждой строки, создавая новый объект класса User и заполняя этот объект данными в этой строке. Да, это создаст проблемы для вас, и Rails знает об этом.

Вы можете использовать:

User.find_each do |user| 
    # do your thing 
end 

find_each даст вам 1000 записей за один раз, таким образом уменьшая операции памяти.

Можно перезаписать значение по умолчанию, обеспечивая batch_size в find_each:

User.find_each(batch_size: 3000) do |user| 
    # do your thing 
end 
0

Я пытаюсь создать временные temp_user_notes таблицы, которые могут иметь данные обеих таблиц, на которых я могу выполнить ActiveRecord запросы для извлечения данные.

Более стандартный способ сделать это - просто присоединиться к двум таблицам. Если используется следующий пункт:

User.joins(:notes) 

, то это даст вам объем, который можно использовать для дальнейшего выполнения запросов (например, вы можетедобавить where условия на обеих таблицах) и возвращаемые записи будут включать столбцы из обеих моделей User и Note, например .:

User.joins(:notes).where("notes.impact_score > 10") 

Даст вам с высоким достаточно счетом все ноты, вместе с присоединенными пользователями.

Если вам нужно пройти через все объединенные записи, вы должны использовать find_each method, который возвращает записи в партиях.

+0

Я согласен @BoraMa использовать соединения - эффективный способ сделать это, но это не решает мою цель. Мое требование: у меня есть серия запросов, разделенных условиями И и ИЛИ. например: 1. user_list = (Query1 или Query2) 2. принимая user_list в качестве входных данных 3. user_list = user_list И Query3 4. user_list = user_list (fulfillig условие 3) И Query4 в последнем списке пользователей у меня есть мой целевых пользователей и там заметки. – Prem

Смежные вопросы