2

最近,我支持的一个团队遇到了一个问题,他们在 MySQL 数据库中存储(和检索)一个值。他们告诉我他们将逗号分隔的值存储在 (VARCHAR(255)?) 列中。

他们报告说他们的值被默默地截断(他们的代码主要是 Ruby,其他一些处理是在 Scala 中完成的)并要求我们将该列的大小加倍。

自然地,我建议他们规范化......将这些值中的每一个(以前以逗号分隔)存储在单独的行中,并使用 SELECT 来获取集合(以前应该是单行)。他们回击并坚称他们永远不希望将这些分隔值用于任何其他类型的数据库查询,并且他们永远不需要该字段比新的 (512) 宽度更宽。

然后我建议他们至少添加一个标记字符串结尾的标记(特别是尾随分号)并在所有提取时检查它。他们已经实现了这一点,并对这种方法感到满意。

我的问题:

  • 他们的数据是如何被悄悄截断的?MySQL 或他们的 Ruby 数据库驱动程序中是否有一些设置可以抑制错误?
  • 与更规范化的方法相比,这种哨兵终止值的优缺点是什么?
  • 这个哨兵终止值是否有一些艺术术语或昵称?
  • 有什么更好的方法来解决他们的问题?
4

2 回答 2

1

在 MySQL 中“错过”截断实际上很容易,但也很容易让它严厉地通知你而不是试图提供帮助。

来自 MySQL 手册:

如果未启用严格 SQL 模式并且您为 CHAR 或 VARCHAR 列分配的值超过了列的最大长度,则该值将被截断以适应并生成警告。对于非空格字符的截断,您可能会导致发生错误(而不是警告)并使用严格的 SQL 模式禁止插入值。请参阅第 5.1.6 节,“服务器 SQL 模式”。

如手册所示,您可以设置 MySQL 的几种“严格”模式之一,以在这种情况下引发错误(以及许多其他会导致静默截断或替换值的错误)。

于 2012-04-25T01:27:58.357 回答
1

如果您的数据库中没有启用严格模式,MySQL 将截断不适合varchar(n)列的字符串,并仅生成有关截断的警告。如果你启用严格模式,那么在这种情况下你会得到一个错误(并且更安心)。

您的哨兵值的最大问题是他们只在读取时检查它。这意味着他们可以(并且肯定会)最终存储无效/损坏的数据,但在尝试解压缩该数据之前他们不会知道问题;但是,当他们解包数据时,要恢复丢失的数据为时已晚。

有各种更好的方法:

  1. 正确规范化的表。
  2. 在 MySQL 中启用严格模式。
  3. 预插入或预更新长度验证。
  4. 如果他们实际上在使用 Rails,那么也许他们可以使用serialize自动将数据转换为/从 ( cringe ) YAML;在这种情况下,他们必须使用更大的 TEXT 列类型,并且仍然存在截断问题。

所以23应该立即完成,1是最好的,如果他们害怕(或不理解)规范化,4可能是一个中间选项。

于 2012-04-25T01:31:27.433 回答