Массовое обновление / вставка Django - PullRequest
0 голосов
/ 01 мая 2018

Я получаю финансовые данные для примерно 5000 инструментов каждые 5 секунд, и мне необходимо обновить соответствующие записи в базе данных. Модель выглядит следующим образом:

class Market(models.Model):
    market = models.CharField(max_length=200)
    exchange = models.ForeignKey(Exchange,on_delete=models.CASCADE) 
    ask = models.FloatField()
    bid = models.FloatField()
    lastUpdate = models.DateTimeField(default = timezone.now)

Что должно произойти, так это:

  • После получения новых финансовых данных проверьте, существует ли запись в база данных.
  • Если запись существует, обновите поля ask, bid и lastUpdate
  • Если запись не существует, создайте новую запись

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

bi_markets = []
for item in dbMarkets:
    eItem = Market.objects.filter(exchange=item.exchange,market=item.market)
    if len(eItem) > 0:
        eItem.update(ask=item.ask,bid=item.bid)
    else:
        bi_markets.append(item)

#Bulk insert items that does not exist
Market.objects.bulk_create(bi_markets)  

Однако выполнение этого занимает слишком много времени. Примерно 30 секунд. Мне нужно сократить время до 1 секунды. Я знаю, что это можно сделать, как я делаю то же самое с пользовательским кодом SQL в .NET менее чем за 100 мс. Есть идеи, как улучшить производительность в Django?

Ответы [ 2 ]

0 голосов
/ 01 мая 2018

Я решил разделить обновление и создать функциональность. Создание происходит только при запуске приложения, оттуда я делаю обновления, используя собственный скрипт SQL. Увидеть ниже. Работает отлично.

updateQ = []
updateQ.append("BEGIN TRANSACTION;")

for dbItem in dbMarkets:
    eItem = tickers[dbItem.market]
    qStr = "UPDATE app_market SET ask = " + str(eItem['ask']) + ",bid = " + str(eItem['bid']) + " WHERE exchange_id = " + str(e.dbExchange.pk) + " AND market = " + '"' + dbItem.market + '";'
    updateQ.append(qStr)

updateQ.append("COMMIT;")

updateQFinal  = ''.join(map(str, updateQ))

with connection.cursor() as cursor:
    cursor.executescript(updateQFinal)
0 голосов
/ 01 мая 2018

Если вы стремитесь к такой производительности, я не понимаю, почему бы вам просто не перейти на сырой SQL. Массовое создание вещей, которых еще нет, звучит как продвинутый SQL-запрос, для которого Django действительно не предназначен.

https://docs.djangoproject.com/en/2.0/topics/db/sql/

Вы также можете сделать (извините на мобильном телефоне):

bi_markets = []
for item in dbMarkets:
  rows = Market.objects.filter(exchange=item.exchange, market=item.market).update(ask=item.ask, bid=item.bid)
  if rows == 0:
    bi_markets.append(item)

Market.objects.bulk_create(bi_markets)

Может быть, эта комбинация сгенерирует более качественный SQL и обойдёт вызов exists() (update возвращает количество измененных строк).

...