Задать вопрос
fox_12
@fox_12
Расставляю биты, управляю заряженными частицами

Django и таблицы с очень большим количеством данных?

Есть БД на postgresql. Есть Django скрипт который собирает данные.
Проблема в том что данных ОЧЕНЬ много. Таблица, с которой необходимо оперировать, содержит, по скромным подсчетам, - от сотен миллионов строк. И похоже - оперировать придется уже миллиардами.
Все частые запросы, - то что можно было закешировать, - я загнал в кеш redis.
Файлы для парсера - загоняются целиком в память и там делается парсинг для ускорения, поскольку файлы грузятся из сравнительно медленного соединения.
Парсеры с помощью celery грузят данные в несколько потоков.
Проблема в том, что на десятках миллионов запросы к админке уже начали отваливаться по таймаутам.
Скорость сбора данных - также оставляет желать лучшего. За полутора суток - собралось десятки миллионов данных - а должны собраться сотни.
Какие еще подходы можно применить для ускорения работы с большим объемом данных?

Структура таблицы с самым большим количеством данных имеет вид:
class CDRData(models.Model):
    start_time_of_date = models.DateTimeField(null=True, blank=True)
    origination_source_number = models.ForeignKey(ANIData, null=True, blank=True, verbose_name='ANI')
    origination_destination_number = models.ForeignKey(DNISData, null=True, blank=True, verbose_name='DNIS')
    routing_digts = models.CharField(max_length=32, null=True, blank=True)
    origination_host = models.GenericIPAddressField(null=True, blank=True, verbose_name='TERMINATION_IP')
    termination_host = models.GenericIPAddressField(null=True, blank=True)
    termination_media_ip = models.ForeignKey(MediaIP, null=True, blank=True, verbose_name='TERMINATION_MEDIA_IP')
    egress_response = models.ForeignKey(EgressResponse, null=True, blank=True,
                                        related_name='d_egress_resp')
    orig_term_release = models.CharField(max_length=32, null=True, blank=True)
    egress_code = models.CharField(max_length=64, null=True, blank=True)
    pdd = models.IntegerField(null=True, blank=True)
    egress_call_duration = models.IntegerField(null=True, blank=True)
    cdr_file = models.ForeignKey('ParsedFile', null=True, blank=True)

    def __str__(self):
        return '{} - {}'.format(str(self.origination_host), str(self.termination_host))

    class Meta:
        verbose_name = 'CDR data'
        verbose_name_plural = 'CDR data'
  • Вопрос задан
  • 2247 просмотров
Подписаться 6 Средний 3 комментария
Пригласить эксперта
Ответы на вопрос 3
baldr
@baldr
Создать много небольших одинаковых таблиц для вставки (например для каждого часа). В этих таблицах убрать все constraints (foreign key, indexes, ...), в них импортировать csv файлы напрямую средствами базы (load from если база умеет).
На момент вставки - понизить уровень изоляции транзакций до минимума (MyISAM раньше идеальна была для таких вставок именно из-за отсутствия транзакций).
Эти таблицы можно уже потом для выборки либо связать через view, либо через более сложные процедуры партиционирования.
Если в течение дня (ночи?) есть какие-то промежутки времени когда база используется мало - можно запустить тяжелый скрипт, который переложит данные из этих таблиц в одну большую и добавит индексы и ключи.
Вставку данных желательно делать в одной транзакции. Если через ORM - то bulk_insert.
Если все это не помогает или не нравится - то улучшайте железо (как можно больше памяти) и настройки базы тяните, но это уже от безысходности.
Учтите, что лучше писать в базу с 3 коннектов, но большими порциями, чем с 30 коннектов но маленькими. Каждый коннект - отдельная транзакция и при закрытии транзакций базе приходится ее согласовывать с остальными текущими.
Ответ написан
Комментировать
@gad26032
1. Сбор данных:
Копай в сторону очередей, воркеров и тд. Паралельный сбор будет быстрее. Тем более что судя по всему ты сканишь всея интернет. Вкратце:
  • Создаешь задание для сканирования и помещаешь в сервер очередей.
  • Запускаешь кучу воркеров в на vps и они из этой очереди будут брать задания и выполнять
  • делаешь еще одну очередь для записи результатов в базу и поднимаешь парочку воркеров для записи в базу. Если каждый сканящий воркер будет напрямую писать в базу то скорее всего ты сам себе заддосиш базу
  • технологии: Очереди- RabbitMQ или Redis. Воркеры - Celery, Мониторинг - Flower

2.
Коллеги выше написали про оптимизацию базы. Это очень важно.
Добавляй индексацию на поля. (На те по которым делаешь фильтр. Например даты.)
Сразу почувствуешь прибавку скорости при запросах.
Ответ написан
Я бы посмотрел в сторону реляции и связей данных, возможно ли упростить выборку, применить что-то типа справочников, и проверять группы записей. Например по start_time_of_date и origination_source_number.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы