Django 表格包含百万行

13 投票
7 回答
12851 浏览
提问于 2025-04-15 17:56

我有一个项目,里面有两个应用程序(书籍和阅读器)。

书籍应用程序有一个表格,里面有400万行数据,包含以下字段:

 book_title = models.CharField(max_length=40)
 book_description = models.CharField(max_length=400)

为了避免查询这个有400万行的数据库,我在考虑按主题来划分数据(20个模型,每个模型有20个表,每个表有20万行,比如书籍_恐怖、书籍_戏剧等等)。

在“阅读器”应用程序中,我打算加入以下字段:

reader_name = models.CharField(max_length=20, blank=True)
book_subject = models.IntegerField()
book_id = models.IntegerField()

所以我不打算用外键,而是想用一个整数“书籍主题”(这样可以访问到相应的表)和“书籍ID”(这样可以在“书籍主题”指定的表中找到具体的书籍)。

这样做能避免查询一个有400万行的表吗?

有没有其他的解决方案?

7 个回答

2

你没有说你使用的是哪个数据库。有些数据库,比如MySQL和PostgreSQL,默认的设置非常保守,基本上只适合在小型服务器上处理小型数据库,其他情况下几乎无法使用。

如果你告诉我们你用的是哪个数据库,运行在什么样的硬件上,以及这些硬件是否和其他应用共享(比如它是否也在服务一个网页应用),那么我们可能能给你一些具体的优化建议。

举个例子,使用MySQL时,你可能需要调整InnoDB的设置;而使用PostgreSQL时,你需要修改shared_buffers和一些其他的设置。

13

ForeignKey 在数据库中是用 IntegerField 来实现的,所以这样做几乎不会节省什么空间,但会让你的模型变得很麻烦。

补充:为了上天的份儿,尽量把数据放在一个表里,并且适当地使用索引。

18

就像很多人说的,把你的表拆分成更小的表(比如横向分区或者分片)有点太早了。数据库本来就能处理这么大的表,所以你的性能问题可能出在别的地方。

首先要考虑的是索引,听起来你已经做过了。对于400万行的数据,数据库加上索引应该能处理得了。

其次,检查一下你运行的查询数量。你可以用像django debug toolbar这样的工具来查看,通常你会惊讶于有多少不必要的查询在被执行。

接下来是缓存,使用memcached来缓存那些大多数用户都不会改变的页面或页面的一部分。这是你能看到最大性能提升的地方,而且所需的努力很少。

如果你真的非常需要拆分表,最新版本的django(1.2 alpha)可以处理分片(比如多数据库),你也可以手动写一个横向分区的解决方案(postgres提供了一种在数据库内部实现的方法)。请不要用类型来拆分表!选择一些你永远不会改变的东西,并且在查询时总能知道的,比如作者的姓的首字母来进行划分。这会需要很多努力,并且对于一个并不特别大的数据库来说有很多缺点——这就是为什么大多数人建议不要这样做的原因!

[编辑]

我忘了提到反规范化!把一些常见的计数、总和等放在比如作者表里,以避免在常见查询中进行连接。缺点是你得自己维护这些数据(直到django添加一个DenormalizedField)。我建议在开发过程中针对一些简单明了的情况考虑这个,或者在缓存失效后再考虑——但一定要在分片或横向分区之前。

撰写回答