1

我是 Django 新手,我有一个应用程序,它的数据库中有大约 60,000 个“项目”模型。

这个数量一直在增长,“项目”是我们制作的 Django 模型。我们的应用程序通常需要按特定顺序在我们的网站上显示这些项目。我们有 3 种类型的项目,我将它们称为 type1、type2、type3。这些项目也会在某个时间到期,而且数量一直在增长,所以我们不能创建一个静态列表并使用它,它必须是动态的。我们需要显示项目,例如(每页 32 个):

type1 type2 type3 type1
type2 type3 type1 type2 
type3 type1 type2 type3
type1 type2 type3 type1
type2 type3 type1 type2
type3 type1 type2 type3
type1 type2 type3 type1
type2 type3 type1 type2 

我们还实现了无限滚动来显示这些项目,因此列表需要保持相同的顺序。例如:上面的第 2 页将以 type3 开头。

  1. 现在我们按每种类型进行 3 个查询。
  2. 为每个创建一个列表。
  3. 创建另一个列表。
  4. 然后迭代并以交替顺序将项目附加到 3 中的列表中。
  5. 创建一个 Paginator 并返回特定页面。

我知道这是非常昂贵的,创建所有这些列表并遍历它们,但我正在努力寻找一种加速它的方法。我尝试过的一种方法是Memcached

我在 Memcached 中存储了 1500 个项目,并且响应非常快。但是当密钥过期时,应用程序必须再次经历所有这些。我想到的一件事是创建一个管理命令(https://docs.djangoproject.com/en/dev/howto/custom-management-commands/)并从 crontrab 运行它以确保此列表始终在内存中。我们已经在 crontab(我们的数据提取)中运行了一些命令,所以这不会很糟糕。

我还尝试利用这样一个事实,即您可以使用过滤器创建一个 QuerySet,并且它在实际需要之前不会进入数据库。但由于我们每页显示 32 个项目,因此在实际实现时遇到了麻烦。这是因为它将显示一种类型的 10 个,另一种类型的 11 个和另一种类型的 11 个。

不同种类的量是不一样的。大约有:

类型1:~500
类型2:~36,000
类型3:~24,000

正因为如此,我在 type1 结束时以及 type2 结束时该怎么做时遇到了麻烦(不太可能有人会走到这一步,但仍然需要考虑它)。

编辑:感谢您的回复!这是我学校的顶点项目。这是我们中的任何人第一次使用 python。我之前在实习时使用过 Groovy 和 Grails,所以我熟悉 ORM 的概念。我将提供一些代码:

def index(request):
    type1Projects = list(project.objects.filter(type=type1))
    type2Projects = list(project.objects.filter(type=type2))
    type3Projects = list(project.objects.filter(type=type3))

    projects = list()

    while(len(type1Projects) > 0 or len(type2Projects) > 0 or len(type3Projects) > 0) :
        if(len(type1Projects) > 0) :
            projects.append(type1Projects.pop(0))
        if(len(type2Projects) > 0) :
            projects.append(type2Projects.pop(0))
        if(len(type3Projects) > 0) :
            projects.append(type3Projects.pop(0))

    paginator = Paginator(projects, 32)

    page = request.GET.get('page', 1)
    render_to_response('fake.html', {'projects':paginator.page(page)}, RequestContext(request))

如您所见,评估这些查询并将列表加载到内存中会产生很多开销。然后迭代和创建项目列表也需要一段时间。

在我们的顶点客户想要交替的类型之前,我们只是返回如下:

def index(request) :
    projects = projects.objects.all()

    paginator = Paginator(projects, 32)

    page = request.GET.get('page', 1)
    render_to_response('fake.html', {'projects':paginator.page(page)}, RequestContext(request))

这些是这个函数的简化版本,只是为了演示这个概念。第二个速度很快,因为它只评估它需要什么。交替方式花费的时间太长了,因为所有内容都加载到内存中然后迭代。

这是我试图利用 Django QuerySet 延迟评估的版本:

def index(request) :
    type1Projects = project.objects.filter(type=type1)
    type2Projects = project.objects.filter(type=type2)
    type3Projects = project.objects.filter(type=type3)

    page = request.GET.get('page', 1)

    type1Pag = Paginator(type1Projects, 11)
    type2Pag = Paginator(type2Projects, 11)
    type3Pag = Paginator(type3Projects, 11)

    type1List = list(type1Pag.page(page))
    type2List = list(type2Pag.page(page))
    type3List = list(type3Pag.page(page))

    projects = list()

    while(len(type1List) > 0 or len(type2List) > 0 or len(type3List) > 0) :
        if(len(type1List) > 0) :
            projects.append(type1List.pop(0))
        if(len(type1List) > 0) :
            projects.append(type2List.pop(0))
        if(len(type3List) > 0) :
            projects.append(type3List.pop(0))


    render_to_response('fake.html', {'projects':projects}, RequestContext(request))

这个版本确实工作得更快,这是一个比实际实施更简单的版本,因为有逻辑可以告诉从哪个项目类型开始,并将其限制为每页 32 个项目。但是它每页错过了一种类型的项目。一旦你到达更远的页面,我正在努力实现从此类列表中的项目 #5 开始的逻辑,然后转到下一页。

我希望这能澄清一点,抱歉昨晚让我感到困惑......我正在为决赛做准备,昨晚很累/可能没有好好思考。我将研究原始 SQL 和 NoSql。

@Saransh Mohapatra 直接使用 Redis 或 Memcache 到底是什么意思?我们现在使用 Memcache 来存储列表中的前 1500 个项目。问题是我们只希望我们的密钥在 5-10 分钟内有效。因此,当密钥过期然后有人访问该站点时,他们的响应速度很慢。这就是为什么我在谈论创建一个管理命令,然后使用 crontab 每 4 分钟运行一次,并让密钥在 10 分钟内有效。如果我们这样做了,那么列表将始终存在,但我不确定这是解决此问题的最佳方法。

4

1 回答 1

0

如果不查看您的代码,很难提出任何建议。但据我猜测,您的模型没有关系,因此如果使用 NoSql 而不是使用传统的 sql,它会快得多。

它会使它更快,你不必每次都缓存。您可能会查看 Reddis 甚至直接使用 memcache,而不仅仅是将其用于缓存。这些基本上是一种键值存储,因此在您的缓存项目中可以是键及其详细信息值。看一看

于 2012-12-01T08:24:21.147 回答