为模式匹配搜索索引jsonb数据

Nee*_*pta 4 postgresql indexing pattern-matching jsonb

这是对jsonb键/值的模式匹配的后续跟进

我有一张桌子如下

CREATE TABLE "PreStage".transaction (
  transaction_id serial NOT NULL,
  transaction jsonb
  CONSTRAINT pk_transaction PRIMARY KEY (transaction_id)
);
Run Code Online (Sandbox Code Playgroud)

我的事务jsonb列中的内容看起来像

{"ADDR": "abcd", "CITY": "abcd", "PROV": "",
 "ADDR2": "",
 "ADDR3": "","CNSNT": "Research-NA", "CNTRY": "NL", "EMAIL": "@.com",
             "PHONE": "12345", "HCO_NM": "HELLO", "UNQ_ID": "", 
             "PSTL_CD": "1234", "HCP_SR_NM": "", "HCP_FST_NM": "",
             "HCP_MID_NM": ""}
Run Code Online (Sandbox Code Playgroud)

我需要搜索查询,如:

SELECT transaction AS data FROM   "PreStage".transaction
WHERE  transaction->>'HCP_FST_NM' ILIKE '%neer%';
Run Code Online (Sandbox Code Playgroud)

但我需要让我的用户灵活地搜索任何键/值.

对上一个问题的回答建议将索引创建为:

CREATE INDEX idxgin ON "PreStage".transaction
USING gin ((transaction->>'HCP_FST_NM') gin_trgm_ops);
Run Code Online (Sandbox Code Playgroud)

哪个有效,但我也想索引其他键.因此尝试了类似的事情:

CREATE INDEX idxgin ON "PreStage".transaction USING gin
((transaction->>'HCP_FST_NM'),(transaction->>'HCP_LST_NM') gin_trgm_ops) 
Run Code Online (Sandbox Code Playgroud)

哪个不起作用.这里最好的索引方法是什么,或者我必须为每个键创建一个单独的索引,在这种情况下,如果将新的键/值对添加到数据中,该方法将不是通用的.

Erw*_*ter 8

@jjanes指出的语法错误,
对于一些流行键(包含在许多行中和/或经常搜索)以及许多更罕见的键(包含在少量行和/或很少搜索中),新键可能会动态弹出)我建议这个组合:

流行键的Trigram索引

您似乎不会经常在一次搜索中组合多个键,并且具有多个键的单个索引将变得非常大且缓慢.所以我会为每个热门密钥创建一个单独的索引.使其成为大多数行中未包含的键的部分索引:

CREATE INDEX trans_idxgin_HCP_FST_NM ON transaction  -- contained in most rows
USING gin ((transaction->>'HCP_FST_NM') gin_trgm_ops);

CREATE INDEX trans_idxgin_ADDR ON transaction  -- not in most rows
USING gin ((transaction->>'ADDR') gin_trgm_ops)
WHERE transaction ? 'ADDR';
Run Code Online (Sandbox Code Playgroud)

等等.在我之前的回答中详细说明:

基本的jsonb GIN索引

如果您有许多不同的键和/或动态添加新键,您可以使用基本(默认)jsonb_opsGIN索引覆盖其余键:

CREATE INDEX trans_idxgin ON "PreStage".transaction USING gin (transaction);
Run Code Online (Sandbox Code Playgroud)

除此之外,这支持搜索.但是你不能将它用于值的模式匹配.

询问

结合处理两个索引的谓词:

SELECT transaction AS data
FROM   "PreStage".transaction
WHERE  transaction->>'HCP_FST_NM' ILIKE '%neer%'
AND    transaction ? 'HCP_FST_NM';  -- even if that seems redundant.
Run Code Online (Sandbox Code Playgroud)

第二个条件恰好匹配我们的部分索引.

所以无论是有针对给定的(流行/通用)密钥的特定巽索引,有至少找到包含稀土键(少数)的行的索引-然后筛选匹配的值.相同的查询应该给你两全其美.

一定要运行最新版本的Postgres,最近有成本估算的各种更新.Postgres使用良好的估计和当前的表统计信息来选择最佳查询计划至关重要.


jja*_*nes 5

没有内置索引可以精确执行您想要的操作,搜索精确的键和相应的通配符匹配值,而无需提前指定要使用的键。应该可以创建一个扩展来执行此操作,但这将是一项艰巨的工作,而且我不知道有任何扩展存在。

开箱即用的最佳选择可能是将 jsonb 转换为文本并索引该文本:

create index on transaction using gin ((transaction::text) gin_trgm_ops);
Run Code Online (Sandbox Code Playgroud)

然后向您的查询添加辅助条件:

SELECT transaction AS data FROM transaction
WHERE  transaction->>'HCP_FST_NM' ILIKE '%neer%'
AND transaction::text ilike '%neer%';
Run Code Online (Sandbox Code Playgroud)

现在,它可以使用索引查找包含“neer”的任何内容,然后重新检查“neer”是否出现在“HCP_FST_NM”键的值中,而不是仅出现在JSONB.

如果您的查询词出现在所需键值以外的许多地方,那么这可能不会给您带来很好的性能。例如,如果有人搜索:

transaction->>'EMAIL' ilike '%ADDR%'
AND transaction::text ilike '%ADDR%';
Run Code Online (Sandbox Code Playgroud)

假设所有记录具有与您显示的结构相同的结构,索引将返回每一行,因为每一行都包含“ADDR”,因为用作键。然后,每一行都会无法通过其他条件检查,但前提是做了很多工作之后。