我正在使用PostgreSQL数据库进行Django项目,在该项目中,我需要在具有约1M条记录的用户配置文件表上运行有时复杂的查询,并且返回的数据集可以为0到所有1M记录之间的任何地方。我的问题是,一旦我抓到所有记录,就希望能够进一步过滤它们以在这些配置文件上运行分析。无法在同一请求/响应循环中完成分析,因为除了最小的查询集之外,所有其他查询集都将超时。因此,我正在使用异步javascript触发针对我想要的每种分析类型的新请求。
例如,我将在初始请求中获取所有个人资料,然后发送后续请求以获取这些个人资料,并向我返回性别百分比或具有特定职位的用户百分比,等等。问题是,每个后续请求都必须再次运行原始查询。我想做的是以某种方式缓存该查询,然后在配置文件表的此子集上运行我的查询,而不必执行长时间运行的原始查询。
我试图使用缓存功能来缓存查询集本身,但这实际上会降低性能,我认为是因为必须对查询集进行酸洗或酸洗,然后它仍然必须运行?我还尝试从父级长查询中缓存一个ID列表(这可能是一个非常长的列表,最多1M整数),这使我的系统完全停止工作,无法存储超过44k条记录。
以前有没有人处理过此类问题?我知道我可以在我的路线图上建立一个工作程序/队列系统,但是如果有一个简单的解决方案可以利用Django的内置功能,那就太好了。
一些示例代码:
def get_analytics(request):
data_type = request.POST.get('data_type')
query_params = request.POST.get('query_params') # a crazy filter with lots of Q objects
profile_ids = get_profiles(query_params) # I WANT TO CACHE THIS
profiles = Profile.objects.filter(id__in=profile_ids).distinct()
if data_type == 'overview':
return profiles.count()
else if data_type == 'gender':
gender_breakdown = profiles.filter(a_filter_for_gender).values('gender').annotate(Count('gender', distinct=True))
return gender_breakdown
def cache_function(length):
"""
A variant of the snippet posted by Jeff Wheeler at
http://www.djangosnippets.org/snippets/109/
Caches a function, using the function and its arguments as the key, and the return
value as the value saved. It passes all arguments on to the function, as
it should.
The decorator itself takes a length argument, which is the number of
seconds the cache will keep the result around.
"""
def decorator(func):
def inner_func(*args, **kwargs):
if hasattr(settings, 'IS_IN_UNITTEST'):
return func(*args, **kwargs)
key = get_cache_key(func.__name__, func.__module__, args, kwargs)
value = cache.get(key)
if key in cache:
return value
else:
result = func(*args, **kwargs)
cache.set(key, result, length)
return result
return inner_func
return decorator
@cache_function(60*2)
def get_profiles(query_params):
return Profile.objects.filter(query_params).values_list('id')
为什么缓存ID会减慢系统速度?有没有更好的方法可以做到这一点?