在 Firebird 中使用 VarChar 或 Char 而不是 Integer 时的性能、空间和其他观察

Posted

技术标签:

【中文标题】在 Firebird 中使用 VarChar 或 Char 而不是 Integer 时的性能、空间和其他观察【英文标题】:Performance, space and other observations when using VarChar or Char instead of Integer in Firebird 【发布时间】:2018-09-18 21:35:07 【问题描述】:

我经常使用 Integer 类型的列来指定记录的某些“类型”,因此 0=TypeA、1=TypeB 等等。我可以在列描述中进行翻译,但值本身并不是人类可读的。该列也可以被索引。

另一种情况是,有时记录有一些简短的唯一字母数字字符串作为标识符。此外,我添加了一个 Integer ID 作为主键(并且对于该名称只有一个唯一索引),因为有人告诉我,出于性能原因,主键不应该是字符串。在我从名称中获得 ID 后,我会尽可能使用它。

所以问题是,关于在可以使用整数的地方直接使用字符串,您能告诉我哪些性能、空间和其他观察结果?这些字符串可以很短,比如 8 个字符甚至更少,7 位 ASCII 就足够了。

这个问题主要针对Firebird 3.0,但我也对一般规则或 Firebird 与 MSSQL 等其他数据库的比较非常感兴趣。

这个问题不是关于使用自然主键而不是代理主键。

【问题讨论】:

I can put a translation into the column description 或者您可以使用字典表。你甚至可以给它加上外键。但它也有性能权衡。 have some short unique alphanumeric string as identifier - 这个标识符是否来自外部世界,来自“业务领域”?如果是这样,您将进入“真实与人工PK”的火焰战。以个人为例,我正在制作一个内部小型实用程序。对于客户表,我选择 INN(合法的唯一纳税人识别号)作为 PK。 “有什么可能出错的……”。原来 - 部署后 - 一些天才 游说同一家银行的不同办事处将拥有相同的 INN,尽管有时位于不同的城市(并且位置是 INN 的一部分)。另一个打击是,事实证明我们有一些具有不同税号的外国客户。也可能在单一州内唯一的不同税号可能会在各个方面发生冲突。因此,简而言之,我不得不紧急将生产中的系统从“真正的 PK”(VarChar(11)) 改造成那个非常抽象的整数。试图节省消除冗余让我突然完全缺乏灵活性 【参考方案1】:

没有固定的规则,总是需要权衡取舍。不要过于笼统,要考虑用例、易用性和潜在开销

通常首选整数值,因为它们会导致较小的索引。 Firebird 中的数字索引(64 位整数除外)使用 64 位双精度,这意味着(忽略前缀和后缀压缩等优化),数字索引中的条目将是 8 个字节。

对于字符,它将是声明的最大字符数 x 字符集中每个字符的最大字节数,因此 CHAR(8) CHARACTER SET UTF8 将消耗 8x4=32 个字节,而 CHAR(8) CHARACTER SET WIN1252 在索引(再次忽略一些优化)。

换句话说,如果您使用的那些字符串是 8 个字符或更少,使用单字节字符集(在这种情况下,即使是 7 位字符集,如 ASCII 仍将使用完整字节!),那么将没有使用整数或字符串值之间的显着差异。

此外,如果主键将被另一个表中的外键作为目标,并且您使用代理,则现在需要添加一个联接才能查找该代码,而该代码将立即可用如果您刚刚将其直接用作主键。必须进行额外连接的性能影响可能超过使用代理的任何预期性能“好处”。

与软件开发中的所有内容一样,这是一种权衡。如果字符串代码仍然很小,例如 8 个或更多字符,并且您知道字符串代码不需要更改(级联更新等),那么请务必:选择字符串代码。

另一方面,如果字符串代码需要定期更改(这会导致级联更新),请使用代理项。如果字符串代码大于 16 个字节,请考虑同时实现两者并执行实际(!)性能测试。如果字符串代码很长(比如 50 个字节或更多),则倾向于使用代理项。

【讨论】:

以上是关于在 Firebird 中使用 VarChar 或 Char 而不是 Integer 时的性能、空间和其他观察的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Excel 或 CSV 文件加载到 Firebird 中?

我可以在 Firebird POSITION 函数中使用通配符吗

如何在 Firebird 2.1 中优化此查询?

Postgres vs Firebird [关闭]

Firebird isql 和 ODBC 连接的区别

Firebird rownum * 或 * linq 样式跳过并采取