Django 模型选择:IntegerField 与 CharField

2024-01-08

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 吗?因为我只有一小部分选择,基于整数字段的查询比基于 text/varchar 的查询更有效。”

所以,据我了解,我有两个选择*:

*我意识到可能存在第三种选择,因为低基数索引字段可能不会带来显着的改进 https://dba.stackexchange.com/a/101096,但由于我的值具有 [1%-99%] 分布(并且我正在寻找 1% 部分),因此索引该字段似乎是一个有效的选项。

  • A)只需索引该字段,并将其保留为 CharField。

    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)
    
  • B)执行迁移以将该字段转换为 SmallIntegerField(我不希望它是 BooleanField,因为可能可以向该字段添加更多选项),然后对该字段建立索引。

    A_EVENT = 1
    B_EVENT = 2
    
    types = (
        (A_EVENT, 'Event A'),
        (B_EVENT, 'Event B')
    )
    
    event_type = models.SmallIntegerField(choices=types, db_index=True)
    

Option A

Pros:简单

Cons: 查菲尔德 https://docs.djangoproject.com/en/1.9/ref/models/fields/#charfield基于索引的效率低于基于整数的索引

Option B

Pros:基于整数的索引比查菲尔德 https://docs.djangoproject.com/en/1.9/ref/models/fields/#charfield基于索引

Cons:我必须执行一个复杂的操作:

  1. 架构迁移以创建新的小整数字段 https://docs.djangoproject.com/en/1.9/ref/models/fields/#smallintegerfield
  2. 数据迁移将数百万个实例从旧字段复制(并转换)到新字段。
  3. 更新项目代码以使用新字段或执行另一次架构迁移以将新字段重命名为前一个字段。
  4. 删除旧字段。

总而言之,这里真正的问题是:

将字段迁移到 SmallIntegerField 所带来的性能提升值得冒这个风险吗?

我倾向于尝试选项 A,并检查性能改进是否足够。


我还在 StackOverflow 上提出了这个问题,因为出现了一个更通用的问题:

  • 在任何情况下,在 Django 选择中使用 CharFields 是否比使用 Boolean/Integer/SmallIntegerField 更好?

这种情况的产生是因为在定义项目模型时我受到了启发Django 文档代码片段 https://docs.djangoproject.com/en/1.9/ref/models/fields/#choices:

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)

为什么他们可以使用整数时却使用字符,因为它只是一种永远不应该显示的值表示形式?


计数查询的速度。

UserEvent.objects.filter(event_type=UserEvent.B_EVENT).count()
# elapsed time: 0:00:06.921287

不幸的是,当表中有大量条目时,这种性质的查询在数据库中总是很慢。

Mysql通过查看索引来优化count查询假设索引列是数字 https://dev.mysql.com/doc/refman/5.6/en/where-optimizations.html。因此,如果您使用的是 mysql,但显然您不是,那么这是使用 SmallIntegeField 而不是 Charfield 的一个很好的理由。您的里程因其他数据库而异。我不是 SQL Server 方面的专家,但我的理解是它是特别不擅长使用索引 http://itknowledgeexchange.techtarget.com/sql-server/why-is-my-select-count-running-so-slow/在 COUNT(*) 个查询上。

分区

您可以通过对数据进行分区来提高涉及 event_type 的查询的整体性能。由于当前索引的基数很差,因此规划器通常最好进行全表扫描。如果数据已分区,则仅需要扫描该特定分区。

Char 或 Smallint

char(2) 和小 int 哪个占用更多空间?答案是,这取决于您的字符集。如果字符集只需要每个字符一个字节,那么小整数和 char(2) 将占用相同的空间量。由于该字段的基数非常低,因此在这种情况下使用 char 或smallint 不会产生任何显着差异。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Django 模型选择:IntegerField 与 CharField 的相关文章

随机推荐

  • SwiftUI 如何添加带有回调的自定义修饰符

    在 SwiftUI 中你可以编写如下代码 List ForEach users id self user in Text user onDelete perform delete 我尝试添加功能 onDelete我的自定义组件的语法方法 s
  • 如何删除 CMake 中的特定系统包含目录

    有没有办法告诉 CMake 排除某些系统包含路径 例如 我定义了 string h 两次 一次在 usr include c v1 libc 中 一次在 usr include 中 当我编译时出现以下错误 error functions t
  • 改变箭头的箭头()

    我想知道是否可以更改用 绘制的箭头的箭头arrows 我查看了文档 但我发现我可以更改行尾但不能更改箭头 plot c 1 10 arrows 0 0 10 10 任何帮助表示赞赏 如中所解释的 arrow 您可以使用length and
  • 基于jsonb寻找合适的EAV结构

    我想知道在 jsonb 上构建 EAV 的正确方法是什么 我有Attribute gt Values表与标准 EAV 中的表一样 CREATE TABLE attribute values id INTEGER attribute id I
  • 重构代码后使用 NetDataContractSerializer 进行反序列化时出现问题

    我遇到过这样的情况 我使用 NetDataContractSerializer 序列化一些 NET 对象 并将 XML 存储在数据库中 作为记住应用程序中这些对象的状态的一种方式 最近我刚刚遇到第一种情况 即属性和类型名称的某些代码重构导致
  • 虚拟连续内存与物理连续内存

    虚拟连续内存在物理上也总是连续的吗 如果不是 如何在物理上不连续的 RAM 块上分配和映射虚拟连续内存 感谢详细的回答 简短的回答 您不必关心 除非您是内核 驱动程序开发人员 对你来说都是一样的 更长的答案 相反 实际上连续的内存是通常不会
  • Angular 2:子路由的多个

    使用 Angular 2 有什么方法可以让子路由不显示到主标签中
  • 如何在 GitKraken 中查看提交?

    使用 GitKraken 来检查提交似乎是不可能的 正如您所看到的 没有选项可以签出较旧的提交 只能Cherrypick commit但我不知道这有什么好处 编辑 我可以通过控制台使用另一个 git 程序 git bash 结帐 现在在 G
  • 如何使用 --header 选项通过 Siege 发送 cookie?

    我刚刚开始使用 Siege 在新的 Web 服务器上进行负载 压力测试 我正在尝试测试我的资源 性能最重的脚本 但该脚本需要cookie 在 siege 中使用 header 选项的正确格式是什么 我尝试过这个但没有运气 siege hea
  • 通过具有 NaN 值的数据帧更新数据帧

    我尝试更新 DataFrame df1 pd DataFrame data A 1 2 3 4 B 5 6 7 8 通过另一个 DataFrame df2 pd DataFrame data B 9 np nan 11 np nan 现在我
  • 计算列存储聚合计数

    我希望计算列存储来自另一个表的计数总计 我该怎么做 以下工作是否有效 创建表样本 列 1 AS SELECT COUNT FROM table2 PERSISTED 对于 SQL Server 您可以使用索引视图 http technet
  • “检查 S3 通用/方法一致性...警告”的说明

    我试图理解 S3 功能的 R CMD 检查警告 因此 这是我的情况的一个完全可重现的示例 包括 R 代码和 roxygen 代码 我永远无法在任何地方找到 S3 的完整示例 并且包中的实际使用要么过于复杂 要么记录不足 因此 希望这对其他实
  • 懒加载Spring bean

    如果一个bean是延迟加载的 那么延迟加载的bean中定义的所有bean都会被延迟加载吗 即使它们没有定义 Lazy 这是测试项目 https github com madhur conditional property test blob
  • 在 64 位环境中使用 32 位 COM 对象

    我在 Win7 64bit 上使用 powershell 3 我正在尝试通过以下命令使用 net of excel 32bit microsoft office interop excel xl文件格式 我得到了这个错误 无法找到类型 mi
  • 在 R 中编织为 PDF

    我是 R 新手 正在尝试将 R Markdown 文件编织成 PDF 格式 我不断收到错误消息 pandoc 找不到 pdflatex pdf输出需要pdflatex 错误 pandoc 文档转换失败 错误 41 执行停止 未检测到 TeX
  • 有哪些使用有限元来求解结构二维和三维框架的 python 库? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • python 关闭文件描述符问题

    我认为这个问题更多的是 编码风格 而不是技术问题 说我有一行代码 buf open test txt r readlines 文件描述符会自动关闭 还是会留在内存中 如果文件描述符未关闭 关闭它的首选方法是什么 如果将文件对象分配给变量 则
  • 直接在主页登录/注册

    例如 我希望用户可以直接登录主页 而不是在页面 account login 上登录 我应该做什么才能使它成为可能 如何将主页上的输入字段与 allauth 连接 我不知道这是否太复杂而无法以这种方式工作 有一个适合我的解决方案 这不是最佳解
  • 有没有办法使用 OpenLayers 更改 openstreetmap 中某些要素的颜色?

    我正在使用 OpenLayers 来显示 openstreetmap 有没有办法编辑地图上的某些功能 例如改变水的颜色 消除国家之间的边界等 如果不能使用 JavaScript 来完成 我猜还有其他方法可以做到这一点 比如托管您自己的地图版
  • Django 模型选择:IntegerField 与 CharField

    TL DR 我有一个包含数百万个实例的表 我想知道应该如何为其建立索引 我有一个使用 SQL Server 作为数据库后端的 Django 项目 在生产环境中拥有大约 1400 万个实例的模型后 我意识到遇到了性能问题 class User