Оптимизировать пост-запрос для большого набора данных - PullRequest
0 голосов
/ 03 марта 2020

Существует таблица базы данных Postgress, содержащая около 4 миллионов строк информации о продукте. Доступные столбцы: идентификатор продукта, SKU, штрих-коды продукта (array field) и описание продукта, et c. Здесь пользователи будут загружать CSV файлы данных о продукте. Каждый продукт может содержать несколько штрих-кодов. Данные будут обновлены на основе существующих штрих-кодов продуктов из БД. Если штрих-код уже существует, строка продукта из файла CSV будет пропущена, или продукт не будет добавлен из CSV. В противном случае будет добавлена ​​новая строка с информацией о продукте, и будет создана задача для ручной проверки вставленного продукта. Процесс проверки выполняется администратором вручную. Поэтому мне нужно проверять каждую строку перед вставкой данных в таблицу, и время запроса очень велико, так как существует большое количество данных. Столбец штрих-кода уже проиндексирован.

Запрос, который я использовал, чтобы проверить, существует ли штрих-код:

SELECT * FROM retail_retailinventory WHERE ARRAY['*****'] <@ barcodes

Однако, если какое-либо совпадение не найдено, мне нужно вызвать 5 вставок в разные модели, например Инвентарь, PosModel и модель задачи. Все зависимы. Таким образом, эта операция должна запускаться синхронно. Я пытался использовать bulk_create, но пока не удалось, так как мне нужно поддерживать отношение внешнего ключа между моделями. Этот процесс вставки заполняет большую часть памяти и происходит тайм-аут.

Есть ли способ оптимизировать процесс? Или какая-либо область применения машинного обучения в этом случае? Меня беспокоит то, что если я применяю ML, машину нужно обучать каждый раз, когда в базу данных вставляется новая строка, и это не будет хорошим решением.

Любые предложения приветствуются.

Спасибо.

Ответы [ 2 ]

0 голосов
/ 03 марта 2020

Вы можете создать индекс:

create index on retail_retailinventory using GIN (barcodes)

Затем переписать предложение WHERE так:

WHERE ARRAY['*****'] <@ barcodes
0 голосов
/ 03 марта 2020

Если память процесса, выполняющего этот процесс, не является проблемой, вы можете сделать следующее:

from itertools import chain
existing_barcodes = set(chain.from_iterable(RetailInventory.objects.all().values_list('barcodes', flat=True)))

while csv_processing:
    line = # next csv line
    if line['barcode'] in existing_barcodes:
        continue

В идеале вы могли бы ограничить начальную выборку только соответствующими продуктами. Так может быть, дважды повторить CSV? Первый для получения продукта и штрих-кодов, чтобы вы могли видеть, что на самом деле является новым в одном запросе, а затем второй для их обработки.

...