【发布时间】:2020-11-30 17:18:49
【问题描述】:
我们正在 PostgreSQL 12/13 上试验 JSONB,看看它是否比一堆扩展表(EAV,我猜)更适合可定制的扩展属性,到目前为止,我对结果印象深刻,尽管使用 GIN索引比一开始看起来更棘手。
实验表很简单:
create TABLE jtest (
id SERIAL PRIMARY KEY,
text text,
ext jsonb
);
CREATE INDEX jtest_ext_gin_idx ON jtest USING gin (ext);
我正在使用(更大版本的)这个巨大的块(仅引用 db-fiddle)插入一些不同的数据:
DO 'BEGIN
FOR r IN 1..100000 LOOP
IF r % 10 <= 3 THEN
-- some entries have no extension
INSERT INTO jtest (text, ext) VALUES (''json-'' || LPAD(r::text, 10, ''0''), NULL);
ELSEIF r % 10 = 7 THEN
-- let''s add some numbers and wannabe "dates"
INSERT INTO jtest (text, ext)
VALUES (''json-'' || LPAD(r::text, 10, ''0''), (''{'' ||
''"hired": "'' || current_date - width_bucket(random(), 0, 1, 1000) || ''",'' ||
''"rating": '' || width_bucket(random(), 0, 1, 10) || ''}'')::jsonb);
ELSE
INSERT INTO jtest (text, ext)
VALUES (''json-'' || LPAD(r::text, 10, ''0''), (''{"email": "user'' || r || ''@mycompany.com", "other-key-'' || r || ''": "other-value-'' || r || ''"}'')::jsonb);
END IF;
END LOOP;
END';
各种精确值匹配操作很容易,GIN 非常适合这些操作。但我们也需要
示例查询是:
select * from jtest
where ext->>'hired' >= '2020-06-01' -- not using function index on its own
但是如果我添加语义上无用的并且索引开始:
select * from jtest
where ext->>'hired' >= '2020-06-01'
and ext?'hired';
问题 #1:我可以在我们的应用程序中实现查询解释器以使其正常工作,但这是预期的行为吗? PG不知道用>=的时候左边确实不为空吗?
我还在(ext->>'hired') - fiddle here 上尝试了功能索引:
CREATE INDEX jtest_ext_hired1_idx ON jtest ((ext->>'hired'));
CREATE INDEX jtest_ext_hired2_idx ON jtest ((ext->>'hired')) WHERE ext ? 'hired';
第二个索引比第一个小很多,我不确定第一个是什么好。
问题 #2:当我使用 ext->>'hired' >= '2020-06-01' 执行查询时,它使用小提琴中的第一个 - 但在我的 15M 行测试中没有(只有 18k 行返回)。所以这是第一个混淆 - 我不想在小提琴上重新创建的内部测试(它会执行太久)应该更具体 - 但无论出于何种原因使用顺序扫描。为什么它在更大的表上使用顺序扫描?
答案 #2:在运行ANALYZE 之后,它确实做到了,并且变得很快。因为这不是最重要的问题,所以我在这里直接回答。
最后,不是问题,额外的AND ext ? 'hired' 它使用jtest_ext_hired2_idx 索引就好了(在小提琴和我更大的表中)。
问题#3:相当笼统,这甚至是正确的方法吗?如果我希望对 JSONB 中的值使用比较和 LIKE 操作,我可以用额外的功能索引来覆盖它吗?对于我们的案例来说,它似乎仍然比添加自定义列或连接扩展表更灵活,但它不能在未来咬我们吗?
【问题讨论】:
-
附注:dbfiddle.uk 适用于美元报价。
-
是的,我后来发现了一个,但已经转换了我的,我更喜欢 db-fiddle 或 sqlfiddle 的 UX。 dbfiddle.uk 插入所有行的速度也慢了很多倍。如果其他小提琴手理解美元报价,那肯定会很好。 :-(
-
顺便说一句:您实际上不需要 DO 块来生成测试数据:db-fiddle.com/f/2mRXT4wGjM2ZSftjgKyZce/14
-
哇,这是一个整洁的。我不知道如何使用来自
generate_series的r,非常感谢。 :-)
标签: postgresql indexing jsonb