Как перебрать таблицу базы данных с большим количеством записей - PullRequest
0 голосов
/ 05 января 2019

Я использую библиотеку Scrapy, чтобы почистить сайт, где люди продают автомобили.

Я использую функции Python и IBM Cloud и Scrapy для достижения этой цели. Идея состоит в том, чтобы ежедневно очищать сайт с помощью действий IBM Cloud и добавлять каждое транспортное средство в таблицу vehicles в базе данных Postgres. Эта часть отлично работает.

Структура таблицы vehicles выглядит следующим образом:

enter image description here

На первом шаге в таблицу vehicles добавлено все, кроме столбца данных (данные об автомобиле, которые необходимо добавить на втором шаге). Это отлично работает.

Второй шаг - каждый день проверять каждый добавленный автомобиль из таблицы vehicles, существует ли он на сайте (его можно удалить или продать). На этом шаге я добавляю каждое зацикленное транспортное средство к таблице daily_run_vehicle. Структура daily_run_vehicle выглядит следующим образом:

enter image description here

Если автомобиль существует, я очищаю детали и обновляю таблицу vehicles, столбец data и устанавливаю для столбца handled значение ИСТИНА в таблице daily_run_vehicle. Если он продан или удален, то я увеличиваю столбец retries в таблице daily_run_vehicle.

Второй шаг должен выполняться каждый день.

Сначала я перебираю каждое транспортное средство из vehicles, для которого столбец handled в таблице daily_run_vehicle не равен ИСТИНА или если handled имеет значение Ложь, но число retries равно 5 или более. И для каждой итерации я добавляю новую запись в таблицу daily_run_vehicle.

Действие prepare-get-vehicles и код следующий:

import json
import requests
from common.db import add_logs, get_vehicle_references
from common.db import capture_error
from common.common import APIHOST, NAMESPACE, USER_PASS


def execute_reference(reference, reference_url):
    action = "prepare-get-vehicle"
    url = APIHOST + "/api/v1/namespaces/" + NAMESPACE + "/actions/" + action
    response = requests.post(url,
                             data=json.dumps({"reference": reference, 'reference_url': reference_url}),
                             params={"blocking": "false"},
                             auth=(USER_PASS[0], USER_PASS[1]),
                             headers={"Content-Type": "application/json"})
    print(response.json())


def main(params):
    try:
        for reference in get_vehicle_references():
            execute_reference(reference[0], reference[1])

        return {"Success": "prepare-get-vehicles action executed successfully."}
    except Exception as e:
        capture_error(str(e))
        return {"Failure": "prepare-get-vehicles action NOT executed successfully."}

Функция get_vehicle_references выглядит следующим образом:

def get_vehicle_references():
    conn = db_connection()
    cur = conn.cursor()
    try:
        s = "SELECT reference, reference_url FROM vehicles v WHERE (NOT EXISTS (select reference from daily_run_vehicle WHERE (handled = %s or (handled = %s and retries >= %s)) AND reference = v.reference))"
        cur.execute(s, (True, False, 5))
        return cur.fetchall()
    except Exception as e:
        capture_error(str(e))
    conn.close()

prepare-get-vehicle действие ничего не делает, кроме добавления новой записи в таблицу daily_run_vehicle, и оно выглядит следующим образом:

def main(params):
    try:
        insert_daily_run_vehicle(params.get("reference", None), params.get("reference_url", None))
        return {"Success.": "The DB filler (daily_run_vehicle) is successfully executed."}
    except Exception as e:
        capture_error(str(e))
        return {"Failure": "The DB filler (daily_run_vehicle) action NOT executed successfully."}

Но проблема в том, что таблица vehicles содержит более 300 тыс. Записей, и она с каждым днем ​​становится все больше и больше. Чем цикл for в действии prepare-get-vehicles занимает много времени для выполнения в IBM Cloud. Время ожидания 600 с, но цикл for занимает намного больше времени.

Любой совет, как мне решить мою проблему и как я могу перебрать таблицу, содержащую более 300 тыс. Записей, и для каждой записи добавить новую строку в daily_run_table?

Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 05 января 2019

Для обработки больших дБ таблицы вы можете читать строки таблицы в пакетном режиме, для каждого пакета запускайте новое действие программно, каждое действие может выполняться параллельно, каждое из которых занимает до 600 с.

Например, если у вас есть таблица 300 КБ, переберите строки таблицы в определенном порядке, например, 100 КБ в каждом пакете. Затем вы можете параллельно запускать 3 действия программно, каждое действие обрабатывает каждую партию по 100 КБ.

0 голосов
/ 05 января 2019

Если идентификатор автомобиля не меняется, вы можете сделать это:

INSERT INTO vehicle (id, reference, ...etc...) VALUES (1, 'ref', ...etc...) ON CONFLICT DO NOTHING;

Вставить без зацикливания в существующую строку. Вы даже можете сделать обновление на конфликт http://www.postgresqltutorial.com/postgresql-upsert/

...