该模块实现 hstore 数据类型,用于在单个 PostgreSQL 值中存储键/值对的集合。这在多种场景下很有用,例如包含许多很少被查看的属性的行,或半结构化数据。键与值就是简单的文本字符串。
该模块被视为“可信”模块,也就是说,拥有当前数据库 CREATE 权限的非超级用户也可以安装它。
hstore 外部表示 #
用于输入与输出的 hstore 文本表示包含零个或多个以逗号分隔的
key =>
value 对。一些示例:
k => v foo => bar, baz => whatever "1-a" => "anything at all"
键对的顺序无关紧要(输出时也未必会重现)。键对之间或 => 符号周围的空白会被忽略。包含空白、逗号、= 或 > 的键与值要用双引号包裹。要在键或值中包含双引号或反斜杠,请用反斜杠转义。
hstore 中的每个键都是唯一的。如果你声明一个带重复键的 hstore,只有一个会被存储在 hstore 中,并且无法保证保留的是哪一个:
SELECT 'a=>1,a=>2'::hstore; hstore ---------- "a"=>"1"
值(而非键)可以是 SQL NULL。例如:
key => NULL
NULL 关键字不区分大小写。给 NULL 加上双引号即可把它视为普通字符串 “NULL”。
请记住,hstore 文本格式在用于输入时,其解析发生在任何必需的引号或转义处理之前。如果你通过参数传递 hstore 字面量,则无需额外处理。但如果把它作为带引号的字面量常量传递,那么任何单引号字符以及(取决于 standard_conforming_strings 配置参数的设置)反斜杠字符都需要被正确转义。关于字符串常量处理的更多信息,请参见
Section 4.1.2.1。
在输出时,键与值总是被双引号包围,即使并非严格必要。
hstore 操作符与函数 #
hstore 模块提供的操作符见 Table F.6,函数见 Table F.7。
Table F.6. hstore 操作符
操作符 描述 示例 |
|---|
返回与给定键关联的值;不存在则返回
|
返回与给定键关联的值;不存在的键对应
|
连接两个
|
|
|
|
左操作数是否包含右操作数?
|
左操作数是否包含于右操作数?
|
从左操作数中删除该键。
|
从左操作数中删除这些键。
|
从左操作数中删除与右操作数中的键对相匹配的键对。
|
用
|
把
|
把
|
Table F.7. hstore 函数
除这些操作符与函数之外,hstore 类型的值还可以被下标访问,使其表现得像关联数组。只能指定一个 text 类型的下标;它被解释为一个键,并获取或存储相应的值。例如,
CREATE TABLE mytable (h hstore);
INSERT INTO mytable VALUES ('a=>b, c=>d');
SELECT h['a'] FROM mytable;
h
---
b
(1 row)
UPDATE mytable SET h['c'] = 'new';
SELECT h FROM mytable;
h
----------------------
"a"=>"b", "c"=>"new"
(1 row)
如果下标为 NULL 或该键在 hstore 中不存在,下标读取返回 NULL。(因此,下标读取与 -> 操作符差别不大。)下标为 NULL 时下标更新会失败;否则它会替换该键的值,如果该键尚不存在则向 hstore 添加一个条目。
hstore 为 @>、?、?& 与 ?| 操作符提供 GiST 与 GIN 索引支持。例如:
CREATE INDEX hidx ON testhstore USING GIST (h); CREATE INDEX hidx ON testhstore USING GIN (h);
gist_hstore_ops GiST 操作符类将一组键/值对近似为位图签名。其可选整数参数 siglen 决定签名的长度(字节)。默认长度为 16 字节,有效值介于 1 与 2024 字节之间。更长的签名可获得更精确的搜索(扫描更少比例的索引与更少的堆页面),代价是索引更大。
以签名长度 32 字节创建此类索引的示例:
CREATE INDEX hidx ON testhstore USING GIST (h gist_hstore_ops(siglen=32));
hstore 还为 = 操作符支持 btree 或 hash 索引。这允许将 hstore 列声明为 UNIQUE,或在 GROUP BY、ORDER BY 或 DISTINCT 表达式中使用。hstore 值的排序顺序并没有特别的用处,但这些索引对等值查找可能有用。按如下方式为 = 比较创建索引:
CREATE INDEX hidx ON testhstore USING BTREE (h); CREATE INDEX hidx ON testhstore USING HASH (h);
添加键,或用新值更新现有键:
UPDATE tab SET h['c'] = '3';
另一种做法是:
UPDATE tab SET h = h || hstore('c', '3');
如果要在一个操作中添加或更改多个键,连接方式比下标方式更高效:
UPDATE tab SET h = h || hstore(array['q', 'w'], array['11', '12']);
删除键:
UPDATE tab SET h = delete(h, 'k1');
把 record 转换为 hstore:
CREATE TABLE test (col1 integer, col2 text, col3 text);
INSERT INTO test VALUES (123, 'foo', 'bar');
SELECT hstore(t) FROM test AS t;
hstore
---------------------------------------------
"col1"=>"123", "col2"=>"foo", "col3"=>"bar"
(1 row)
把 hstore 转换为预定义的 record 类型:
CREATE TABLE test (col1 integer, col2 text, col3 text);
SELECT * FROM populate_record(null::test,
'"col1"=>"456", "col2"=>"zzz"');
col1 | col2 | col3
------+------+------
456 | zzz |
(1 row)
使用 hstore 中的值修改现有记录:
CREATE TABLE test (col1 integer, col2 text, col3 text); INSERT INTO test VALUES (123, 'foo', 'bar'); SELECT (r).* FROM (SELECT t #= '"col3"=>"baz"' AS r FROM test t) s; col1 | col2 | col3 ------+------+------ 123 | foo | baz (1 row)
由于 hstore 类型内在的宽松性,它可能包含大量不同的键。检查键的有效性是应用程序的任务。下面的示例演示了检查键和获取统计信息的几种技术。
简单示例:
SELECT * FROM each('aaa=>bq, b=>NULL, ""=>1');
使用表:
CREATE TABLE stat AS SELECT (each(h)).key, (each(h)).value FROM testhstore;
在线统计:
SELECT key, count(*) FROM
(SELECT (each(h)).key FROM testhstore) AS stat
GROUP BY key
ORDER BY count DESC, key;
key | count
-----------+-------
line | 883
query | 207
pos | 203
node | 202
space | 197
status | 195
public | 194
title | 190
org | 189
...................
从 PostgreSQL 9.0 起,hstore 使用的内部表示与以前的版本不同。这对转储/恢复升级不构成障碍,因为(转储中使用的)文本表示保持不变。
在二进制升级的情况下,向上兼容通过让新代码识别旧格式数据来维持。在处理尚未被新代码修改的数据时会带来轻微的性能损失。可以通过如下 UPDATE 语句强制升级表列中的所有值:
UPDATE tablename SET hstorecol = hstorecol || '';
另一种做法是:
ALTER TABLE tablename ALTER hstorecol TYPE hstore USING hstorecol || '';
ALTER TABLE 方式需要对表加 ACCESS EXCLUSIVE 锁,但不会因旧行版本而使表膨胀。
还有额外的扩展为 PL/Perl 与 PL/Python 语言实现 hstore 类型的转换。PL/Perl 的扩展名为 hstore_plperl 与 hstore_plperlu,分别对应可信与不可信 PL/Perl。如果你安装这些转换并在创建函数时指定它们,hstore 值会被映射为 Perl 哈希。PL/Python 的扩展名为 hstore_plpython3u。使用它时,hstore 值会被映射为 Python 字典。
Oleg Bartunov <oleg@sai.msu.su>,俄罗斯莫斯科,莫斯科大学
Teodor Sigaev <teodor@sigaev.ru>,俄罗斯莫斯科,Delta-Soft Ltd.
Andrew Gierth <andrew@tao11.riddles.org.uk>(英国)进行了额外的增强。