我对postgres相当陌生,目前使用的是9.6。 当试图使用它的jsonb文档在postgres中实现全文搜索时,我注意到嵌套数组的搜索结果慢。我使用'explain'命令,它没有使用任何索引。 为了简化目的,我创建了一个表,调查:在PostgreSQL中搜索嵌套JSONB数组元素的索引
CREATE TABLE book (
id BIGSERIAL NOT NULL,
data JSONB NOT NULL
);
我的可用指标:
CREATE INDEX book_author_idx
ON book USING GIN (to_tsvector('english', book.data ->> 'author'));
CREATE INDEX book_author_name_idx
ON book USING GIN (to_tsvector('english', book.data -> 'author' ->> 'name'));
和一些数据来填充文件:
INSERT INTO book (data)
VALUES (CAST('{"author": [{"id": 0, "name": "Cats"}, ' ||
' {"id": 1, "name": "Dogs"}]}' AS JSONB));
我能搜索对于使用以下查询的图书元素,但它不使用任何索引。我的实际数据为12万个产品,大约需要1200毫秒,而其他索引则需要0.2毫秒。
EXPLAIN ANALYZE
SELECT
id,
data ->> 'author' AS author
FROM book, jsonb_array_elements(data #> '{author}') author_array
WHERE to_tsvector('english', author_array ->> 'name') @@ to_tsquery('cat');
相反下一查询使用book_author_name_idx但由于阵列结构没有找到任何东西。
EXPLAIN ANALYZE
SELECT
id,
data ->> 'author' AS author
FROM book
WHERE to_tsvector('english', data -> 'author' ->> 'name') @@ to_tsquery('cat');
如何调整我的查询以使用语言索引? 我知道,我可以为作者创建一个新表格,并只引用id,但我宁愿将所有数据保存在一张表中以获得性能。
在'LATERAL JOIN'中使用'unnest()'和它的朋友(结果集生成函数,如'jsonb_array_elements()')可以防止使用任何索引(至少是从它们算出的属性)。如果你坚持这种结构,你必须创建一个自定义的'IMMUTABLE'函数来从你的'jsonb'列中产生'tsvector'值并在你的索引和查询中使用这个函数。 – pozs
这里有趣的部分是'tsvector'没有任何内置的聚合,所以你需要1)将名称聚合为字符串(带有一些基本规则)2)为'tsvector'构建一个自定义聚合3 )使用一个聪明的递归CTE(因为他们已经存在连接)。 – pozs