TL; DR :我有一个包含数百万个实例的表,我想知道如何索引它。
我有一个使用SQL Server作为数据库后端的Django项目。
在生产环境中建立具有大约1400万个实例的模型后,我意识到我遇到了性能问题:
class UserEvent(models.Model)
A_EVENT = 'A'
B_EVENT = 'B'
types = (
(A_EVENT, 'Event A'),
(B_EVENT, 'Event B')
)
event_type = models.CharField(max_length=1, choices=types)
contract = models.ForeignKey(Contract)
# field_x = (...)
# field_y = (...)
我在此字段中使用了很多查询,由于该字段未编制索引,因此效率非常低。仅通过此字段过滤模型大约需要7秒钟,而通过索引的外键查询不会带来性能问题:
UserEvent.objects.filter(event_type=UserEvent.B_EVENT).count()
# elapsed time: 0:00:06.921287
UserEvent.objects.filter(contract_id=62).count()
# elapsed time: 0:00:00.344261
当我意识到这一点时,我也对自己提出了一个问题:“该字段不应该是SmallIntegerField吗?因为我只有很少的选择集,所以基于整数字段的查询比基于文本/varchar的查询效率更高。”
因此,据我了解,我有两个选择*:
A_EVENT = 'A'
B_EVENT = 'B'
types = (
(A_EVENT, 'Event A'),
(B_EVENT, 'Event B')
)
event_type = models.CharField(max_length=1, choices=types, db_index=True)
A_EVENT = 1
B_EVENT = 2
types = (
(A_EVENT, 'Event A'),
(B_EVENT, 'Event B')
)
event_type = models.SmallIntegerField(choices=types, db_index=True)
选项A
优点:简单
缺点:基于的CharField的索引比基于整数的索引的效率低
选项B
优点:基于整数的索引比基于CharField的索引更有效
缺点:我必须执行一个复杂的操作:
总结一下,这里的真正问题是:
从将字段迁移到SmallIntegerField所获得的性能提高值得冒险吗?
我倾向于尝试选项A,并检查性能改进是否足够。
我还提出了这个问题到StackOverflow,因为出现了一个更通用的问题:
之所以出现这种情况,是因为在定义项目模型时,我受到Django documentation code snippet的启发:
YEAR_IN_SCHOOL_CHOICES = (
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
)
year_in_school = models.CharField(max_length=2,
choices=YEAR_IN_SCHOOL_CHOICES,
default=FRESHMAN)
为什么在使用整数时会使用chars,因为它只是一个永远都不会显示的值表示形式?
最佳答案
计数速度查询。
UserEvent.objects.filter(event_type=UserEvent.B_EVENT).count()
# elapsed time: 0:00:06.921287
不幸的是,当表具有大量条目时,这种性质的查询在数据库中总是很慢。
Mysql通过查看索引provided the indexed columns are numeric优化计数查询。因此,如果您使用的是mysql,则这是使用SmallIntegeField而不是Charfield的一个很好的理由,但显然您没有。您的里程因其他数据库而异。我不是SQL Server方面的专家,但我的理解是,它是COUNT(*)个查询的particularly poor at using indexes。
分区
您可以通过对数据进行分区来提高涉及event_type的查询的整体性能。由于当前索引的基数很差,因此计划人员进行全表扫描通常会更好。如果数据已分区,则仅需要扫描该特定分区。
字符或Smallint
哪个占用更多的空间char(2)或small int?答案是,这取决于您的字符集。如果字符集每个字符仅需要一个字节,则小整数和char(2)将占用相同的空间量。由于该字段将具有非常低的基数,因此在这种情况下使用char或smallint不会有任何显着差异。
关于sql-server - Django模型选择: IntegerField vs CharField,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36702839/