Django 之 CharField 和 TextField

     阅读:40

CharField

test_char = models.CharField(max_length=288)

设置长度为 288 并不会报错,这取决于你的数据库后端,mysql char 类型长度为 255,django 里面设置超过 255 并不会有提示,个人感觉有点误导人,起码给个警告也行,但是在插入数据时,字节数大于 255 会提示:django.db.utils.DataError: (1406, "Data too long for column 'test_char' at row 1"),注意这里不是字符的长度,而是字节长度。
在 Python 中,不同的字符所占的字节数不同,数字、英文字母、小数点、下划线以及空格,各占一个字节,而一个汉字可能占 2~4 个字节,具体占多少个,取决于采用的编码方式。例如,汉字在 GBK/GB2312 编码中占用 2 个字节,而在 UTF-8 编码中一般占用 3 个字节。
如何测试字节长度和字符长度:

str1 = "人生苦短,我用Python"
len(str1)
13
len(str1.encode('utf-8'))
27
len(str1.encode('gbk'))
20

注意:CharField 类型会强制校验 max_length,所以参数必填,在官方文档中解释到:一个长度CHAR列被固定在创建表声明的长度。长度可以是 0 到 255 之间的任何值。CHAR 存储值时,它们会用空格右填充到指定的长度。当CHAR被检索到的值,拖尾的空格被删除,除非 PAD_CHAR_TO_FULL_LENGTH启用SQL模式。所以如果长度设置的过大但实际用时却存储很少的数据时对数据库也是一种压力。

TextField

test_char = models.TextField(max_length=288)

存储长度可以为 0 到 65,535 之间的值,也是字节数,存储方式和 char 类型稍微不同,TextField 因为可以存储短数据和长数据,所以在存储时稍有不同,VARCHAR值存储为 1 字节或 2 字节长度的前缀加数据。长度前缀表示值中的字节数。如果值需要不超过 255 个字节,则列使用一个长度字节,如果值可能需要超过 255 个字节,则使用两个长度字节。
但是需要注意的是,在不同的数据库后端,如果存储的字节数真的符合 65,535 ,那么也会存在一个问题,在 mysql 官方解释中,如果 sql 的包大于 4 M, 也会抛出异常:django.db.utils.OperationalError: (2013, 'Lost connection to MySQL server during query ([WinError 10053] 你的主机中的软件中止了一个已建立的连接。)'),此时要修改 max_allowed_packet 配置, 默认为 4M。

性能比较

CharField 采用定长存储,参数为 max_length 占用的空间就是声明的宽度。
TextField 采用变长存储,存储内容为:实际大小 + 长度记录位。
存储方式对性能是有影响的:
例如:
分别使用 varchar(10) 与 varchar(255) 定义一个字段,实际存储的字符串为 “abcde”
在存储空间方面,他们没有区别,因为 varchar 是变长存储,只占用实际内容的宽度
因为执行查询时,mysql为了优化查询,在内存中对字符串会使用固定的宽度,所以定义的宽度越长,就会消耗更多的内存。
存储方式对I/O性能也有影响,如果使用 varchar 定义了字段,此字段内容还是更新频繁的,例如开始是个长字符串,后来更新为一个短字符串,因为 varchar 占用空间就是字符串实际宽度,那么这时就产生了碎片空间。
在这里插入图片描述
而 char 类型是定长存储,就不会产生存储碎片,有更好的I/O性能

总结

  1. 长度的区别,CharField 范围是0~255, TextField 最长是64k(65,535 bytes)
  2. 效率来说基本是 CharField > TextField
  3. CharField 必须传入 max_length,另一个场景用于在 modelform 中使用,TextField 可以不传参数

选取类型时可以结合已下场景来考虑:

  1. 该字段数据集的平均长度与最大长度是否相差很小,若相差很小优先考虑CHAR类型,反之,考虑VARCHAR类型。
  2. 若字段存储的是MD5后的哈希值,或一些定长的值,优先选取CHAR类型。
  3. 若字段经常需要更新,则优先考虑CHAR类型,由于CHAR类型为定长,因此不容易产生碎片。
  4. 对于字段值存储很小的信息,如性别等,优先选取CHAR类型,因为VARCHAR类型会占用额外的字节保存字符串长度信息

参考文献

mysql 官网:https://dev.mysql.com/doc/refman/8.0/en/char.html
腾讯云:https://cloud.tencent.com/developer/article/1083976
varchar和char的长度和区别:https://www.365jz.com/article/25055