【问题标题】:Is it crazy to bypass database case sensitivity issues by storing original string case AND lower case?通过存储原始字符串大小写和小写来绕过数据库区分大小写问题是不是很疯狂?
【发布时间】:2010-10-25 16:23:32
【问题描述】:

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

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

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

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

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

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

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

例如:表中的两个字段

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

我认为这样做的利弊是:

优点:

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

  2. 索引上的搜索将是干净的,并且永远不会因排序规则或调用 LOWER() 或任何东西而减慢速度(假设这样的事情会减慢索引,这似乎是合乎逻辑的)

缺点:

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

  2. 好像有点野蛮

我知道它会起作用,但同时它闻起来有问题。

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

【问题讨论】:

标签: sql database database-agnostic


【解决方案1】:

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

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

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

【讨论】:

    【解决方案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,是的,那将不得不走桌子。有了功能索引,它就做对了。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • “实用,不疯狂”正是我的看法。但它似乎应该是一个常见问题,我觉得我错过了一些东西,因为我没有看到这样做,也没有看到任何例子。
      • 嗯,有些数据库不支持功能索引。您很可能必须像这样索引数据,因此这将是唯一的选择。我已经看到使用这种索引的严肃应用程序,所以我肯定会说它不是疯狂或不寻常的。在支持功能索引的地方(例如 Oracle 和 Postgre),使用它们可能更有意义。
      【解决方案4】:

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

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

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

      【讨论】:

      • LOWER 会扼杀索引的好处吗?
      • 大多数 DBMS 将无法为此类查询使用索引,这可能是个问题。显而易见的解决方案是基于函数的索引,但并非所有 DBMS 都有它们。此外,如问题中所述,不同 COLLATE 实现的问题仍然存在。
      • @Russ,在 Oracle 中,您可以创建基于函数的索引,以便使用 Lower() 索引的列本身 -- (akadia.com/services/ora_function_based_index_2.html)
      • @Russ:是的,它确实如此,除非您为“LOWER(UserName)”创建基于函数的索引。然而,并不是所有的 DBMS 都有基于函数的索引(例如,Oracle 和 PostgreSQL 有,MySQL 没有)。
      • @sleske - 谢谢 - 我将研究函数基索引,即使在 DBMS 实现中不可用。这不是我以前听说过的。
      猜你喜欢
      • 2012-12-01
      • 1970-01-01
      • 2020-02-18
      • 1970-01-01
      • 1970-01-01
      • 2022-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多