【问题标题】:MySQL: using char(n) vs decimal(n) with zero fillMySQL:使用零填充的 char(n) 与 decimal(n)
【发布时间】:2011-08-24 02:47:37
【问题描述】:

我被要求使用一个数据库,其中大多数主键和其他字段也使用 char(n) 来存储带有填充的数值,例如:

product_id: char(8) [00005677]
user_id: char(6) [000043]
category_id: char(2) [05]

他们想要这样使用它的原因是,如果他们愿意,可以使用字符(在遥远的将来)。但是它们有很多基于数字的规则,例如 category_id 01 到 79 对应一般类别,80 到 89 是特殊类别,90 到 99 是用户自定义类别。

我个人认为使用 char(n) 存储数字是一种不好的做法。我的理由是:

  1. 使用字符," " != 0, 0 != 00, 05 != 5, 00043 != 000043 等等。是因为, 必须不断检查这些值(以防止数据损坏)。
  2. 如果我填充一个数字:0 -> 00,那么我要注意不要填充 一个字符(A -> 0A)
  3. 如果使用字符,则范围会变得奇怪,例如: 从 01 到 79 和 AB 和 RX 和 TZ 和 S 等等......
  4. 索引数字而不是字符可以提高性能

我建议使用 zerofill 将其更改为 decimal(n) 以使其更“防错”,因为此信息由不同来源(Web、Windows 客户端、上传 csv)修改。例如,如果他们想添加更多类别,那么从 decimal(2) 更新到 decimal(3) 会更容易。

那么我的问题是:我错了吗?可以信任 char(n) 来完成这项任务吗?如果“字符”对数字不利,那么我在上面的列表中还遗漏了哪些其他缺点(如果我想赢得我的案子,我可能需要更好的理由)?

TIA(任何评论/答案将不胜感激)。

【问题讨论】:

  • 我会接受谁可以说服我以这种方式使用 char(n) 是完全安全的答案,或者谁可以给我更多为什么不使用 char 的理由。
  • @lepe:根据“最佳实践”,案件本身是荒谬的。前导零与存储无关,而仅与表示有关。只要您希望您的 id 以前导零显示 - 在您将其输出给用户之前 填充它们,并以您喜欢使用的任何格式存储。
  • +1。我完全同意你的看法......恕我直言,突然使用通常只使用数字的字符可能会在未来破坏事情。唯一的原因是他们想记住字符的数量,(这是:99,AA(2 个字符);100(3 个字符))。但我认为这不值得复杂化。如果有必要,增加数字会更容易......但是向他们解释! :S
  • char 在 ANSI SQL 中的所有比较有效地用空格填充在右侧。不确定MySQL是否存在问题。但是在您的情况下, varchar 或 char 没有区别,因为所有这些标识符的长度都应该等于列的容量,因为它们都应该在左边用“0”填充。您还没有提到将来是否所有代码都应该不包含空格并且是全长?
  • 是的,我没有提到,因为现在还不清楚。到目前为止,只使用数字(我们谈论的是 ID)并且所有数字都必须是全长的(用零填充)。但是,如果他们也希望使用字符,我不确定是否允许使用空格……可能,这可能会使事情变得更加复杂。使用字符的唯一原因是拥有更多相同长度的 ID。这就是为什么我认为使用 char(n) 是一种无意义的限制。如果他们想添加更多 ID,那么只需增加数量,恕我直言。

标签: mysql char decimal zerofill


【解决方案1】:

如果这是 SQL Server 或 Oracle 或任何其他 RDBMS,我建议对这些列实施检查约束,以便数据始终与列的全部容量匹配 - 这将确保您的标识符是统一的。

不幸的是MySQL doesn't support this

虽然它不会阻止必须填充进入数据库或搜索例程、客户端或数据库中的 procs 的东西的烦恼,但它可以保证您的字段在最低级别是干净的。

我发现使用这样的约束有助于避免事情严重失控。

就使用数字的优化而言,如果它们将来必须容纳非数字字符,那将不是一个选择。

使用 varchar/char 数据拥有自然键(可能是主键的候选者)是很常见的,但它却强制代理键的引用完整性(通常是某种自动编号整数,它只是一个内部引用,并且通常是聚集索引和主键)。

【讨论】:

  • 是的,使用触发器来填充数据可能是一种选择......我想 CHECK 可以让我的生活更轻松......但我坚持使用 MySQL。所以,基本上你说如果没有这些检查,你的数据可能会严重失控?很久以前,我提议使用内部 AUTOCOUNT 引用,但他们拒绝了这个想法,因为数据的一部分是直接从每个 Windows 客户端导入的,他们认为这只会使事情复杂化。
  • @lepe 如果您不能在数据库中强制执行,任何事情都可能发生。我总是想知道数据库将在它暴露给消费者的周边(表/视图或过程)保证什么服务/完整性。为了减轻没有将其作为声明性约束,您可以有一个每小时/每天的流程来检查潜在问题并将它们扼杀在萌芽状态。使用数据库元数据编写/代码生成和保持更新会相对容易,并给您一些更好的信心。
  • +1 确切地说,“如果你不能在数据库中强制执行它,任何事情都可能发生”:这就是我需要扩展的想法。运行 cron 来检查数据也是一个好主意,如果我无法说服他们,我会考虑的。
  • @lepe 在复杂的系统中,存在一些在数据库级别实现根本不切实际的约束。不仅因为它们是高阶业务逻辑,还因为不值得弄清楚触发器的放置位置——或者触发器可能需要应用于各种相互关联的表。在这种情况下,可以覆盖整个数据模型的自动异常报告是您的朋友。
【解决方案2】:

引用你的问题:

...用填充存储数值...

您没有展示任何数字数据的示例,只展示了恰好由数字组成的字符数据。如果你说他们的OrderTotal 列是 char(10),那我就开始担心了。

只要把它当作字符数据就行了。我看不到更改数据库的业务或技术案例(除非您开始几乎完全重写)。

关于性能...如果这实际上是一个问题,那么您很可能有更大的问题需要处理。 MySQL 快速准确。

--

在某处编写一个函数,将零填充用户输入的 ID 用于查询。在您需要接受用户输入的任何地方使用此功能。永远不要使用数字数据类型来存储您的数据(如果是 PHP,永远不要使用 +,总是使用 . 来连接,等等...)

请记住,这与Item_Number = "SHIRT123" 或您可能遇到的任何其他字符串 ID 没有什么不同

保重

【讨论】:

  • 是的,还有其他字段(如 OrderTotal)使用 int... 没问题。数据库本身很旧(可能有 8 年的历史),但系统完全从零开始重写。 Web 和 Windows 客户端。该系统尚未启动,因此仍有时间提出一些更改。我主要关心的是数据完整性并减少错误的可能性,因为它将被数百个分支机构使用。
  • “只要把它当作字符数据就可以了。我看不到更改数据库的业务或技术案例”:问题在于我不是唯一的开发人员,如果有人错过-检查填充(什么时候是数字)然后您添加损坏的数据。正如 Cade 评论的那样,如果可能的话,我想在数据库中强制执行它(因为数据在不同的客户端中被修改)。
猜你喜欢
  • 2019-03-30
  • 2022-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-14
  • 2021-01-16
相关资源
最近更新 更多