0

我正在实现一个数据库,其中几个表具有字符串数据作为候选键(例如:用户名),并将被相应地编制索引。对于我想要的这些字段:

  1. 当有人在这些键上查询表时不区分大小写

  2. 以某种方式保留最初编写的案例,以便应用程序可以使用原始案例将数据呈现给用户

我还希望数据库模式尽可能独立于数据库,因为应用程序代码不(或不应该)从属于特定的 RDBMS。

另外值得注意的是,对数据库进行的绝大多数查询将由应用程序代码完成,而不是通过客户端直接访问表。

在实现这一点时,我遇到了很多烦人的问题。一是并非所有 RDBMS 都以相同的方式实现 COLLATE(在这种情况下,区分大小写似乎可以在模式级别进行调整)。另一个问题是排序规则和区分大小写选项可以设置在多个级别(服务器、数据库、表(?)、列),我无法向应用程序保证它将获得什么设置。另一个问题是 COLLATE 本身可能会变得毛茸茸,因为除了区分大小写之外,还有更多内容(例如:unicode 选项)。

为了避免所有这些令人头疼的问题,我正在考虑通过为一个数据存储两列来完全避开这个问题。一列使用原始大小写,另一列被应用层降为小写。

eg:表中的两个字段

user_name = "fredflintstone"(这个唯一索引)
orig_name = "FredFlintstone" (只是数据......没有限制)

在我看来,这样做的优点和缺点是:

优点:

  1. 没有歧义 - 应用程序代码将管理案例转换,当底层 RDBMS/设置发生变化时,我永远不需要担心单元测试“神秘地”失败。

  2. 索引上的搜索将是干净的,并且永远不会因整理功能或调用 LOWER() 或任何东西而减慢(假设这些事情会减慢索引,这似乎是合乎逻辑的)

缺点:

  1. 双倍数据需要额外的存储空间

  2. 好像有点野蛮

我知道它会起作用,但同时它闻起来不对劲。

这样做是疯狂/毫无意义吗?是否有什么我不知道的东西使区分大小写的问题不像我现在认为的那样棘手?

4

4 回答 4

2

当然,这样的决定总是需要权衡取舍,但我认为这不一定是“数据翻倍”。小写字符串可能是一项不平凡的操作,特别是如果您超出 ASCII,因此字符串的小写版本不仅仅是“重复”。它与原始字符串有些相关,但仅此而已。

如果您将其视为将计算结果存储在数据库中的类比,它会变得更加自然。

查询选项UPPER(UserName)是另一个很好的解决方案,它避免了第二列。但是,要使用它,您至少需要一个可靠的UPPER函数(特别是您可以控制它用于非 ASCII 字符的语言环境),并且可能需要基于函数的索引以获得良好的性能。

于 2010-10-25T16:26:20.717 回答
2

索引上的搜索将是干净的,并且永远不会因整理功能或调用 LOWER() 或任何东西而减慢(假设这些事情会减慢索引,这似乎是合乎逻辑的)

不,这不合逻辑。您可以对常量函数进行索引。

create index users_name on users(name); -- index on name
create index users_name_lower on users(lower(name)); -- index on the function result

您的 RDBMS 应该足够聪明,知道users_name_lower在收到此查询时可以使用:

select * from users where lower(name) = ?

如果没有 users_name_lower,是的,那将不得不走桌子。使用功能索引,它会做正确的事情。

于 2010-10-25T16:47:55.303 回答
1

建议您的搜索查询执行以下操作:

  • SELECT * FROM Users WHERE LOWER(UserName) = LOWER('fredFlinstone')
  • 当应忽略/尊重区分大小写时,在查询中显式包含 COLLATION 提示

我认为重复数据以区分大小写过于繁琐。

于 2010-10-25T16:26:00.903 回答
1

出于性能原因,我经常看到以这种方式复制数据。它允许您保留原始大小写(您显然需要它,因为您并不总是能够猜出大小写应该是什么,例如,您不能确定每个名称都以大写字母开头)。如果数据库不支持执行此操作的其他方式(功能索引),那么这是实用的,而不是疯狂的。您可以使用触发器保持数据一致。

于 2010-10-25T16:33:14.270 回答