0

我有一个 64 位整数时间戳和一个 Sting 用户名,它们组合成一个字符串并最终存储到一个数据库列中。撇开为什么我不能将它们存储在具有适当类型的单独列中,我的问题是如何组合它们以从底层数据库中获得更好的性能。那将是 sqlite、PostgreSQL 或 MySQL,还不确定。

我想象他们将使用 b-trees 作为索引,并且像 (timestamp-username) 这样连接会很糟糕,因为时间戳通常总是会进行,而树需要经常平衡。username-timestamp 应该要好得多,但每个用户记录仍然会随着每个新条目而增加。我正在考虑也将时间戳与位的相反顺序。

还有什么我可以做的吗?一些聪明的异或什么的?什么是合理的最佳模式?数据将永远通过请求生成的确切字符串来访问,没有范围等。

唯一的要求是在生成的字符串和源数据之间以两种方式进行相对快速的转换。

更新:伙计们,我正在获取信息,哪种字符串更适合作为数据库的主键存储(sqlite、mysql和postgresql之一)。也许答案是没关系,或者取决于数据库引擎。我正在使用的架构或缓存解决方案没有特别的问题。我只是问是否有任何改进的空间以及如何改进。我会很感激一些关于主题的答案。

UPDATE2:对我来说,很好的答案仍然不确定: 增量列是否会使列上的 b-tree 索引不平衡? https://stackoverflow.com/a/2362693/520567

4

2 回答 2

1

您的问题存在矛盾,您指定不能拆分它们并将它们存储在单独的列中,但是您正在谈论分别索引这两个部分 - 如果不拆分它们,您将无法做到这一点。

我可以看到你真的有两个选择:

  1. 将它们存储在单独的列中
  2. 散列输出以降低索引内存占用

理想情况下,如果您总是以相同的顺序一起搜索它们,则应该将它们存储在两列中并创建一个复合索引。在这种情况下,如果不先提供更多信息,就很难给出准确的建议 - 但是,如果您按用户查询,通常用户名,时间戳将是合乎逻辑的,或者如果您想按时间戳查询,则将其反转。如果您需要搜索一个或另一个,您还可以在每列上创建一个索引。

散列生成的字符串

INSERT INTO table (crc_hash_column, value_column_name)
values (CRC32(@generated_value), @generated_value)

会将大小减小到 32 位整数(每行只有 4 字节的索引),远小于所需的等效 VARCHAR 或 CHAR 索引空间。

如果你采用这种方法,那么你应该采取措施避免冲突,由于生日悖论它会发生,并且随着数据集的增长更有可能发生。即使有冲突,考虑到索引的大小,额外的过滤仍然会产生比替代方案更好的性能。

SELECT * FROM table
WHERE crc_hash_column = CRC32(@search_value) 
AND value_column_name = @searchvalue

使用散列会导致更多的 CPU 周期 - 但 CRC32 散列非常快,因此即使您每次搜索时都必须重新散列,但对于索引大量数据所带来的好处而言,这项额外工作是微不足道的。

一般来说,我更喜欢第一个选项,但在不了解您的用例的情况下几乎不可能推荐。

您应该分析这两个选项,看看它们是否符合您的要求。

于 2013-03-27T21:39:53.843 回答
0

你说你不能把它们放在单独的列中(你甚至不能设置一个具有 1:1 关系的新表/使用触发器将数据镜像到物化视图/用更正表上的视图替换现有表结构????!!!!) 意味着任何解决方案都将是一个丑陋的黑客。

是的,数据变化的多少以及它的结构将影响更新的效率。然而,索引的目的是加快检索速度——您没有向我们提供有关如何访问数据/如何更改数据的信息。

我正在考虑也将时间戳与位的相反顺序

为什么?这更有可能加速索引碎片而不是减少它。

MariaDB 支持虚拟列 - 以及虚拟列上的索引,因此您可以做一些愚蠢的事情,例如将规范化规则扔出窗外 - 但如果您无法解决架构中的一个小问题,那么替换 DBMS 可能不会是非常实用的解决方案。

坦率地说,如果花时间和金钱为问题开发一个糟糕的解决方案是值得的,而这个解决方案的成本已经与一个正确的解决方案一样高,并且可能会产生未来的成本,那么选择糟糕的解决方案就是浪费时间和金钱。

于 2013-03-27T22:24:49.680 回答