如果指定值实际上仅适用于一字节字符,如何确定数据库中类似 VARCHAR 类型列的最大字符数?

问题描述 投票:0回答:1

与 CHAR 相比,VARCHAR 值存储为 1 字节或 2 字节 长度前缀加数据。长度前缀表示的数量 值中的字节。如果值不需要,则列使用一个长度字节 超过 255 个字节,如果值可能需要超过两个长度字节 255 字节。

MySQL官方文档

让我们在 EC 商店案例中考虑这个问题。 以下是如何定义产品(项目)实体(即使没有学习 TypeScript,很可能你也能理解这段代码):

import { FIXED_CHARACTERS_COUNT_IN_UNIVERSAL_UNIQUE_ID__VERSION_4 } from "fundamental-constants";


type Product = {
  readonly ID: Product.ID;
  label: string;
  price__dollars__withoutTaxes: number;
};


namespace Product {

  export type ID = string;
  export namespace ID {
    export const TYPE: StringConstructor = String;
    export const REQUIRED: boolean = true;
    export const FIXED_CHARACTERS_COUNT: number = FIXED_CHARACTERS_COUNT_IN_UNIVERSAL_UNIQUE_ID__VERSION_4;
  }

  export namespace Label {
    export const TYPE: StringConstructor = String;
    export const REQUIRED: boolean = true;
    export const MINIMAL_CHARACTERS_COUNT: number = 2;
    export const MAXIMAL_CHARACTERS_COUNT: number = 127;
  }

  export namespace Price__Dollars__WihtoutTaxes {
    export const TYPE: NumberConstructor = Number;
    export const REQUIRED: boolean = true;
    export const MINIMAL_VALUE: number = 0;
  }

}

无论是前端输入的数据验证还是后端请求数据验证(与数据库定义相同)都必须遵守上述业务规则。特别是,产品标签必须包含 2 至 127 个字符:

enter image description here

假设上述值从不在前端和后端直接输入两次 - 相反,它被引用:

<!-- BAD: the maximal characters count has been HARDCODED -->
<label for"PRODUCT_LABEL--INPUT">Please input 2-127 characters.</label>
<input type="text" maxlen="127" id="PRODUCT_LABEL--INPUT" />

<!-- GOOD: the maximal characters count has been referred (no matter what is the template engine)-->
<label for"PRODUCT_LABEL--INPUT">Please input {{ Product.Label.MINIMAL_CHARACTERS_COUNT }}-{{ Product.Label.MAXIMAL_CHARACTERS_COUNT }} characters.</label>
<input type="text" maxlen="{{ Product.Label.MAXIMAL_CHARACTERS_COUNT }}" id="PRODUCT_LABEL--INPUT" />

定义数据库时(现在重要的是,具体如何 - 通过原始 SQL 请求、GUI 工具或 ORM),我们还将为

label
表的
Products
列设置类似 VARCHAR 的类型,最大长度为 127 个字符(再次,参考
Product.Label.MAXIMAL_CHARACTERS_COUNT
而不是直接输入
127
值)。

然后,假设卖家输入的产品标签几乎包含127个字符,但包括2个字节的字符。前端的验证不会像后端请求数据的验证一样威胁到输入的值。但是,一旦服务器应用程序尝试将添加(或更新)的产品保存到表中,我们就会收到有关

label
的值超出最大长度的异常!

问题:

Product.Label.MAXIMAL_CHARACTERS_COUNT
中必须设置哪个值? (让我重复一遍,这个值是从前端和后端referred)。

mysql database varchar
1个回答
0
投票

VARCHAR(L)
列的长度参数指定可以保存多少个字符。这不包括 MySQL 数据库在表中存储值所需的额外字节数。引用的文档仅指定在
VARCHAR
列中存储值还需要多少字节。请参阅以下示例:

mysql> CREATE TABLE Dummy (Label VARCHAR(10));
Query OK, 0 rows affected (0.02 sec)

mysql> INSERT INTO Dummy(Label) VALUES('12345');
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO Dummy(Label) VALUES('123456789');
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO Dummy(Label) VALUES('1234567890');
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO Dummy(Label) VALUES('12345678901');
ERROR 1406 (22001): Data too long for column 'Label' at row 1

如您所见,可以将字符串

123456789
(长度为 9)保存在
VARCHAR(10)
列中,因为 9<=10. It will however require additional 1 byte to save the data.

当您尝试将字符串

1234567890
(长度为 10)保存在
VARCHAR(10)
列中时,它从 10 开始也能正常工作<=10. Again, it needs additional 1 byte for the length of the string.

无法保存值

12345678901
,因为该字符串的长度为 11,并且太大而无法保存在
VARCHAR(10)
类型的列中。

因此,当您只想保存最大长度为127的标签时,请使用

VARCHAR(127)
。用户将能够使用长度不超过 127 的字符串来保存值,但不能使用更大的字符串。

请记住,数据存储为字符,而不是字节。这意味着值

äöüäöüäöü
(九个元音变音)可以保存在
VARCHAR(10)
列中,因为 9<=10, even though 18+1 bytes are needed to save the data in the table. See the following
SELECT
语句:

mysql> SELECT Label, LENGTH(Label) FROM Dummy;
+--------------------+---------------+
| Label              | LENGTH(Label) |
+--------------------+---------------+
| 12345              |             5 |
| 123456789          |             9 |
| 1234567890         |            10 |
| äöüäöü             |            12 |
| äöüäöüöäü          |            18 |
+--------------------+---------------+
5 rows in set (0.00 sec)

mysql> EXPLAIN Dummy;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| Label | varchar(10) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
1 row in set (0.00 sec)
© www.soinside.com 2019 - 2024. All rights reserved.