在 Oracle 和 PostgreSQL 数据库之间移植时混合标识符的缺点

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前,正在 星球 内带小伙伴们做第一个项目:全栈前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 204 小节,累计 32w+ 字,讲解图:1416 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 870+ 小伙伴加入,欢迎点击围观

Oracle 数据库 PostgreSQL 数据库 都使用双引号的存在与否来指示区分大小写或不区分大小写的标识符。这些数据库中的每一个都允许不使用引号(通常不区分大小写)或使用双引号(区分大小写)命名标识符。

区分大小写的带引号/定界符标识符的优点

区分大小写的标识符有很多优点 。区分大小写的数据库标识符的一些宣传的(实际的和感知的)好处包括:

  • 能够使用不带引号的标识符无法使用的保留字、关键字和特殊符号。
    • PostgreSQL 的关键词
      • reserved(“只有真正的关键字”,“永远不允许作为标识符”)
      • 无保留(“在特定上下文中有特殊含义”,但“可以在其他上下文中用作标识符”)。
      • " 带引号的标识符 可以包含任何字符,但代码为零的字符除外。(要包括双引号,请写两个双引号。)这允许构造否则不可能的表或列名称,例如包含空格或&符号的名称。 “
    • Oracle 保留字和关键字
      • Oracle SQL 保留字 只能用作“带引号的标识符,尽管不推荐这样做”。
      • Oracle SQL 关键字 “未保留”,但使用这些关键字作为名称可能会导致“SQL 语句 [that] 可能更难阅读并可能导致不可预测的结果。”
      • “非引号标识符必须以数据库字符集中的字母字符开头。引号标识符可以以任何字符开头。”
      • " 带引号的标识符 可以包含任何字符和标点符号以及空格。"
  • 能够对两个不同的标识符使用相同的字符,大小写是区分特征。
  • 避免依赖数据库实现的案例假设并提供“ 一个通用版本 ”。
  • 明确的大小写规范避免了在某些数据库(例如 SQL Server) 中可能会发生变化的大小写假设问题。
  • 与大多数 编程语言 和操作系统的文件系统 保持一致
  • 在 SQL 规范中指定并明确说明标识符的大小写,而不是依赖于 特定数据库 的特定实现细节(大小写折叠)。
  • 允许外部用户指定要解释为标识符的 SQL 的 情况下的额外保护。

不区分大小写标识符的优点

使用不区分大小写的标识符也有一些好处。可以说不区分大小写的标识符是 Oracle 数据库和 PostgreSQL 数据库中的“默认”,因为必须使用引号来指定何时不区分大小写。

  • 不区分大小写是 Oracle 和 PostgreSQL 数据库中的“默认”。
  • 可读性的最佳案例可以在任何特定上下文中使用。例如,允许将 DML 和 DDL 语句写入特定的编码约定,然后自动映射到各种数据库的适当大小写折叠。
  • 避免不知道或不愿意遵循 大小写约定的 开发人员引入的错误。
  • 双引号 ( " " ) 与单引号 ( ' ' ) 非常 不同 ,至少在 Oracle 和 PostgreSQL 数据库的某些上下文中,不使用区分大小写的标识符双引号消除了 记住 差异 或担心下一个开发人员不记住差异。
  • 上面列出的许多“优势”可能并不是真正的好做法:
    • 无论如何,使用保留字和关键字作为标识符可能不利于可读性。
    • 使用带引号标识符中允许但不带引号标识符中不允许的符号可能没有必要,甚至是不可取的。
    • 拥有两个具有不同字符大小写的同名不同变量可能不是一个好主意。

默认不区分大小写或引用的区分大小写的标识符?

Don't use double quotes in PostgreSQL 中 Reuven Lerner 说明了使用 PostgreSQL 的“默认”(无双引号)不区分大小写的标识符。 Lerner 还指出 pgAdmin 隐式创建了 双引号区分大小写的标识符 。从 Oracle DBA 的角度来看, @MBigglesworth79 将 Oracle 中的引号标识符称为 Oracle Gotcha 并得出结论,“我个人的建议是反对使用引号标识符,因为它们似乎会导致比其价值更多的问题和混乱。”

在辩论引用的区分大小写的标识符与默认的不区分大小写的标识符时要考虑的一个关键权衡是能够(但也需要)明确指定标识符的大小写与不能(但不必)指定标识符中使用的字符大小写。

选择一个或另一个:不要混合它们!

根据我的经验,设计数据库结构时最糟糕的选择是混合区分大小写和不区分大小写的标识符。这些的混合使开发人员很难知道什么时候大小写很重要,什么时候不重要,但是开发人员必须意识到这些差异才能正确使用它们。将标识符与隐式大小写和显式大小写混合肯定会违反 最小意外原则 ,并且几乎肯定会导致令人沮丧的运行时错误。

本次讨论中要考虑的另一个因素是在 Oracle 数据库和 PostgreSQL 数据库中实现的大小写折叠选择。这种 大小写折叠 可能会导致 意想不到的后果 ,尤其是在具有不同大小写折叠假设的两个数据库之间进行移植时。 PostgreSQL 数据库 折叠为小写字符 非标准 ),而 Oracle 数据库折叠为大写字符。这种差异的重要性在第一个 PostgreSQL Wiki Oracle Compatibility Tasks ”中得到了例证:“带引号的标识符,大写与小写折叠。”事实上,虽然我发现 PostgreSQL 非常注重符合标准,但这种大小写折叠行为是一个非常不标准且无法轻易更改的地方。

在同一个数据库中混合区分大小写和不区分大小写标识符的唯一“安全”策略是了解特定数据库的默认大小写折叠策略,并使用与数据库完全相同的大小写来命名甚至明确命名(双引号)的标识符将大小写折叠非引号标识符。例如,在 PostgreSQL 中,可以将引号中的所有标识符命名为完全小写字符,因为 PostgreSQL 会将未加引号的标识符默认为所有小写字符。但是,在使用 Oracle 时,将需要相反的方法:所有带引号的标识符都应全部大写,以允许混合区分大小写和不区分大小写的标识符。当然,当人们试图从这些数据库之一移植到另一个时,就会出现问题,因为小写或大写的假设发生了变化。那么,对于 Oracle 和 PostgreSQL 数据库之间的数据库可移植性,更好的方法是要么在所有地方使用带引号的区分大小写的标识符(然后它们对两个数据库明确命名为相同的),要么在所有地方使用默认的不区分大小写的标识符(并且每个数据库将以自己的方式适当地折叠大小写)。

结论

在 Oracle 数据库和 PostgreSQL 数据库中,具有隐式大小写(不区分大小写)的标识符和具有显式(引用和区分大小写)大小写的标识符都有优势,个人偏好和品味可以影响任何决定使用哪种方法。虽然我更喜欢(至少在撰写本文时)使用隐式(默认)不区分大小写的方法,但我宁愿在所有情况下都使用明确拼写(带双引号)的标识符大小写,而不是混合使用这种方法和使用在某些情况下标识符的显式大小写规范和在其他情况下标识符的大小写隐式规范。混合使用这些方法使得很难知道数据库中每个表和列中使用的是哪个,并且使得在对大小写折叠做出不同假设的数据库(例如 PostgreSQL 和 Oracle)之间移植 SQL 代码变得更加困难。


补充阅读