本文针对目前最新版PostgreSQL 9.5.1,若非说明,文中所说文档即指官方文档。本人刚接触PostgreSQL不久,文中不免错漏,请大家指正;随着了解深入,本文[可能]会不定期更新补足。
JSON
PostgreSQL支持Json格式数据,有两种类型:json和jsonb。两者在效率上有所区别,而这是因为jsonb存储的是格式化后的二进制数据,所以在写入时,json类型比较快,而在检索时(注意这里说的检索不是简单的读取整个数据,而是比如检索json数据中某个键的值的场景),jsonb效率较高。一般情况下,使用jsonb就可以了。json数据是为了弥补关系型数据在伸缩性扩展性上的不足,但是文档也说了,不能啥都往里放,要考虑数据原子性和数据大小。
json类型可以作包含判断和是否存在的判断(containment or existence),表示符号分别为@>和?(以及其它一些变种)。对于这两种牵涉到多个键和元素的判断场景,json类型比下面要讲的arrays更适合,因为其对查询有内在的优化机制,而array只是单纯的线性查找。
若json列需要经常检索,那么可以在其上建立GIN索引,jsonb支持两种特有的GIN索引jsonb_ops和jsonb_path_ops。创建的语法如下:
CREATE INDEX idxgin ON api USING GIN (jdoc); CREATE INDEX idxginp ON api USING GIN (jdoc jsonb_path_ops); -- 只是比前一行多了jsonb_path_ops标记
The jsonb_path_ops supports indexing the @> operator only. 关于这两者使用和技术实现上的区别可参看:PgSQL 9.4 新特性jsonb类型解析,PostgreSQL 9.4 中使用 jsonb
我们可以对json数据中的某一属性建GIN索引(可称之为属性索引),如:CREATE INDEX idxgintags ON api USING GIN ((jdoc -> ’tags’)); 这能提升检索键值对的效率,比如如下场景:
SELECT jdoc->’guid’, jdoc->’name’ FROM api WHERE jdoc -> ’tags’ ? ’qui’;
当然我们也可以不使用属性索引,而是换一种查询方式:
SELECT jdoc->’guid’, jdoc->’name’ FROM api WHERE jdoc @> ’{"tags": ["qui"]}’;
jsonb also supports btree and hash indexes. These are usually useful only if it’s important to check equality of complete JSON documents.
Array
PostgreSQL支持Array类型,其字段声明有如下几种方式:
1 CREATE TABLE emptable ( 2 arraycol1 integer[], 3 arraycol2 text[][], 4 arraycol3 text[3], 5 arraycol4 integer ARRAY, 6 arraycol5 integer ARRAY[4] 7 );
在列声明时我们可以指定数组中的元素类型、维度和长度,后两者然并卵,当前版本的PostgreSQL会忽略这两者的设置,它们更多是以一种备注的意义存在。
插入格式如下:
INSERT INTO emptable VALUES (
’{10000, 10000, 10000, 10000}’,
’{{"meeting", "lunch"}, {"training", "presentation"}}’,
ARRAY[10000, 10000, 10000, 10000],
ARRAY[[’meeting’, ’lunch’], [’training’, ’presentation’]]
);
注意字符串的写法,第3行单引号内部是以双引号包含,第5行ARRAY构造函数方式则是以单引号包含。多维数组中每个元素的长度要一致,否则会报错,比如不能
INSERT INTO emptable VALUES ( ’{10000, 10000, 10000, 10000}’, ’{{"meeting", "lunch"}, {"training"}}’ -- error );
访问,arraycol[n],PostgreSQL的数组默认下标是1基的,这点需要注意,即默认情况下我们访问数组第项应使用arraycol[1],而非惯常的arraycol[0],当然我们可以 SET arraycol[-2:7] = '{XXOO,...}'的方式设置数组的上下界(这个例子就变成了-2基);多维数组访问,以二维数组为例,arraycol[n][m];若下标超出数组长度则返回null,并不会抛出异常。若访问数组某部分毗邻元素,则需要用到slice形式,形如arraycol[1:3][2:5],表示要访问1到3项,并且取这三项中的2到5项——仍以数组形式——返回,第一个中括号表示第1维,第二个表示第2维,以此类推。需要注意的是arraycol[1:3][2],并不是表示取1到3项中的第2项,PostgreSQL认为只要有一个维度是slice形式,则所有你要访问的维度都是slice形式,若只有1位数,则前面附加1:,即arraycol[1:3][2] == arraycol[1:3][1:2]。如果slice的下标超出数组长度,又会怎样呢?有两种情况:若起始下标就超出了,那么返回空数组(文档中说是因为历史原因);若只是结束下标超出,则返回从起始下标到数组末尾这段数据。