Какой вариант лучше для хранения больших данных в приложении Django
Итак, у меня есть приложение Django, над которым я сейчас работаю, это приложение будет делать евклидово расстояние для 2000+ данных. Такое количество данных при запуске, когда веб пользуется высоким спросом, приведет к краху, поэтому я думаю о нескольких решениях, но я не знаю, будет ли это отличаться при развертывании.
Первая идея - вычислить все расстояния и поместить их в жестко закодированную переменную в файле some_file.py. Файл будет выглядеть следующим образом
data = [[1,2,..],[3,4,..],[5,6,..],[7,8,..],...]
и доступ к нему можно получить следующим образом
data[0][2] = 2
этот файл имеет размер 60MB
Вторая идея является основной, я создаю таблицу с 3 столбцами. A, B и euclidean_distances(A,B). Но это решение создаст 4.000.000+ записей.
*ПРИМЕЧАНИЯ
Я использую Postgresql для своей базы данных
Мой вопрос в том, какое решение лучше для сохранения всех расстояний при развертывании? Я открыт для любого другого решения
Возможно, вам вообще не нужно ничего хранить, если евклидовы расстояния - это все, что вы на самом деле собираетесь обслуживать. Я сделал для вас несколько расчетов и приглашаю вас проверить время самостоятельно.
from random import randint
from math import sqrt
class point2d():
x:int
y:int
def __init__(self, x:int,y:int):
self.x = x
self.y = y
def __str__(self):
return f"x:{self.x}, y:{self.y}"
class point3d():
x:int
y:int
z:int
def __init__(self, x:int,y:int,z:int):
self.x = x
self.y = y
self.z = z
def __str__(self):
return f"x:{self.x}, y:{self.y}, z:{self.z}"
def eucdist1d(x:int, y:int) -> int:
return abs(x - y)
def eucdist2d(x:point2d,y:point2d) -> float:
return sqrt((x.x - y.x)**2 + (x.y - y.y)**2)
def eucdist3d(x:point3d,y:point3d) -> float:
return sqrt((x.x - y.x)**2 + (x.y - y.y)**2 + (x.z - y.z)**2)
Теперь рассмотрим следующее:
- Евклидовы расстояния довольно дешевы для вычисления, даже для трехмерных точек.
- Вычисление и хранение 2000 одномерных результатов в виде списка занимает 844 мс процессорного времени, но занимает 130 Мб оперативной памяти. Словарь с теми же данными занимает 340 Мб оперативной памяти, но не дает преимущества в скорости. .
- Для двумерных точек запрос списка действительно быстрее, чем вычисление расстояния, но в среднем только на одну около 500 наносекунд. Однако вы не можете хранить значимое количество точек - даже если вы хотите хранить расстояния только для точек в пределах квадрата 0 =< x < 100 и 0 <= y < 100, то только для хранения списка потребуется 3,3 Гб оперативной памяти.
- Поиск трехмерных точек быстрее, чем вычисление, но занимает 2,8 Гб оперативной памяти только для точек в пространстве (0,0,0) - (19,19,19). Очевидно, что рост памяти кубический, и вычисления расстояний более высокой размерности еще менее пригодны для хранения любого рода.
- Запрос списка или словаря в памяти всегда быстрее, чем запрос к базе данных, где необходимо учитывать сетевую задержку - использование базы данных, на самом деле, с большей вероятностью приведет к сбою в случае экстремального спроса. Не вдаваясь в примеры баз данных, вычисления n-мерного евклидова расстояния с n < 4 вряд ли выиграют от базы данных или вообще от предварительного расчета. .
Вы можете выполнить следующее в ipython или jupyter notebook:
#1D 120MB of RAM
%time eucdatalist1d = [[eucdist1d(x,y) for x in range(0,2000)] for y in range(0,2000)]
%time %timeit eucdatalist1d[randint(0,1999)][randint(0,1999)]
#2D
#Only 50MB of RAM, but then, only storing points (0,0) - (29,29)
%time eucdatalist2d = [[[[eucdist2d(point2d(x,y),point2d(a,b)) for a in range(0,30)] for b in range(0,30)] for y in range(0,30)] for x in range(0,30)]
%time %timeit eucdatalist2d[randint(0,29)][randint(0,29)][randint(0,29)][randint(0,29)]
#3D
#Careful with this one, it takes up 2,8GB RAM and only stores (0,0,0) - (19,19,19)
%time eucdatalist3d = [[[[[[eucdist3d(point3d(x,y,z),point3d(a,b,c)) for a in range(0,20)] for b in range(0,20)] for c in range(0,20)] for y in range(0,20)] for x in range(0,20)] for z in range(0,20)]
%time %timeit eucdatalist3d[randint(0,19)][randint(0,19)][randint(0,19)][randint(0,19)][randint(0,19)][randint(0,19)]
#Note that the ranges below are -4000 to 3999, not limited as above, also, there is no increase in RAM use.
%time %timeit eucdist1d(randint(-4000,4000),randint(-4000,4000))
%time %timeit eucdist2d(point2d(x=randint(-4000,4000),y=randint(-4000,4000)),point2d(x=randint(-4000,4000),y=randint(-4000,4000))
%time %timeit eucdist3d(point3d(x=randint(-4000,4000),y=randint(-4000,4000),z=randint(-4000,4000)),point3d(x=randint(-4000,4000),y=randint(-4000,4000),z=randint(-4000,4000)))
Причина использования %time %timeit заключается в том, чтобы показать среднее значение, а также общее время, необходимое для этих вычислений.
Если вам важны только 1D вычисления, просто пропустите любой вид предварительных вычислений, они того не стоят. Если вам нужно выполнять больше 2D вычислений, чем 145 тысяч в секунду, или больше 3D вычислений, чем 105 тысяч в секунду, инвестируйте значительные средства в оперативную память и используйте предварительно вычисленный список.
Если вы знакомы с Pandas, вы можете сделать все это с помощью Vaex.io. Это именно то, для чего он предназначен. Правильно построив индекс, вы сможете легко нарезать данные на кусочки и получить искомые данные. https://vaex.io/
Я предпочитаю использовать базу данных, особенно если предполагаю, что система будет расти, потому что таким образом можно масштабировать веб-часть и базу данных независимо друг от друга. В целом, похоже, что люди тоже выбирают этот метод
- Хранение больших объемов данных: БД или файловая система?
- Хранение больших данных в файлах против таблиц
- Хранение и доступ к большому количеству относительно небольших файлов
Некоторые другие соображения
- Прочитайте документы по оптимизации доступа к базе данных в Django, чтобы убедиться, что вы будете следовать стандартам - например, делайте работу с базой данных в базе данных, а не в Python .
- Рассмотрите возможность использования репликации базы данных, поскольку это может привести к повышению производительности.
- Рассмотрите возможность использования кэша для повышения производительности и снижения нагрузки на базу данных. Читайте больше о кэш-фреймворке Django.
- Django поддерживает только определенные базы данных.
- Нереляционные базы данных, как правило, лучше подходят для хранения больших объемов данных и уменьшают задержку.
- Django поддерживает использование многочисленных баз данных.
- Django имеет метод
bulk_create()
для вставки данных в базу данных (обычно только с одним запросом).