19

我被要求使用 postgreSQL 数据库,它将取代我目前使用的 berkeleyDB。虽然; 我意识到这不是一个理想的情况,它超出了我的控制范围。

所以问题是……如果你需要将 postgreSQL 变成一个键值存储,你将如何做这件事,同时让它尽可能高效?

我的值是字节数组,我的键是字符串,我可以对这些字符串的长度施加一些限制。

我假设我应该为我的值和主键列使用一个 blob 来保存键,但是当我刚刚冒险进入这个旅程时,我很好奇堆栈溢出社区中是否有人这样做,或者是否有任何特定的“陷阱”我应该注意。

4

5 回答 5

27

Postgresql 中正确执行此操作的扩展名为 hstore。它的工作方式与您期望的其他键值存储系统类似。只需加载扩展程序。语法是独一无二的,但如果你曾经使用过 redis 或 mongo,你会很快得到它。不要让它变得比现在更难。我理解,我们经常无法选择我们的工具,只能勉强凑合。
这是文档页面:

http://www.postgresql.org/docs/9.1/static/hstore.html

于 2012-05-29T02:19:23.670 回答
4

另一种选择是使用 JSON 或 JSONB,键上有唯一的哈希索引。

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

CREATE TABLE key_values (
    key uuid DEFAULT uuid_generate_v4(),
    value jsonb
);

CREATE INDEX idx_key_values ON key_values USING hash (key);

一些查询

SELECT * FROM key_values WHERE key = '1cfc4dbf-a1b9-46b3-8c15-a03f51dde891';
Time: 0.514 ms
postgres=# SELECT * FROM key_values WHERE key = '1cfc4dbf-a1b9-46b3-8c15-a03f51dde890';
Time: 1.747 ms

postgres=# do $$
begin
for r in 1..1000 loop
INSERT INTO key_values (value)
VALUES ('{"somelarge_json": "bla"}');
end loop;
end;
$$;
DO
Time: 58.327 ms

您不能像使用 B-tree 那样运行有效的范围查询,但它应该具有更好的读/写性能。索引应该小 60% 左右。

于 2019-11-27T14:04:30.213 回答
3

如果您被迫使用关系数据库,我建议您尝试在数据中找到结构以利用这一事实,因为您放弃了使用非结构化数据和键值存储获得的速度优势。你找到的结构越多,你摆脱困境的优势就越大。即使您只在键中找到结构。

还要考虑您是否只需要顺序或随机访问您的数据,以及根据此要求以何种比例和结构来构建您的数据库。例如,您是否要按类型查询您的值?这些问题中的每一个都可能影响您构建数据库的方式。

关于 postgresql 中 blob 的一个具体考虑因素,它们在内部表示为 pg_largetable (loid:oid,pageno:int4,data:bytea)。块的大小由 LOBBLKSIZE 定义,但通常为 2k。因此,如果您可以在表中使用字节数组而不是 blob 并在块大小下限制值/键对的大小,则可以通过第二个表避免这种间接。如果您有权访问数据库的配置,也可以增加块大小。

我建议去寻找数据结构和数据访问模式,然后再次详细询问您的问题。

于 2010-01-05T19:26:26.753 回答
0

您需要存储什么作为值?字符串?整数?对象(例如,序列化的 Java 对象)。一个简单的实现将使用一个 3 列的表,如下所示:

NAME(VARCHAR)   TYPE(VARCHAR)   VALUE(VARCHAR)

(也许 TYPE 是一些枚举)。以上不适用于像序列化对象这样的二进制数据,但也许你需要一个 BLOB。

或者(可能是一个更好的主意),你看过Apache Commons Configuration吗?您可以使用数据库(通过 JDBC)支持它,并且可以存储属性以便检索它们:

// get a property called 'number'
Double double = config.getDouble("number");
Integer integer = config.getInteger("number");

这可能会在实施方面为您省去很多麻烦。您可能在保存二进制数据时遇到问题,因为您必须在插入和检索后对其进行序列化。但我过去曾用它来通过 XStream 存储整数、双精度和序列化 Java 对象,因此我可以确认它运行良好。

于 2010-01-05T19:15:34.707 回答
0

它真的应该取决于密钥是什么。如果它始终是 255 个字符以下的字符串,则使用 Varchar 作为 yoru PK,然后使用 blob(假设值很大)作为值。如果它始终是一个数字,请使用 int 等。

换句话说,需要更多信息才能真正给你一个好的答案:)

于 2010-01-05T19:17:01.130 回答