在我的笔记本电脑上运行PostgreSQL 9.6.4,我有一个名为properties
的表,其中包含主键SELECT n.*
FROM node n
WHERE node_type_id = '2'
AND properties @> '{"slug":"wild-castles"}'::JSONB
ORDER BY n.id ASC OFFSET 0 LIMIT 10;
字段和properties
字段。
我在Limit (cost=0.56..1517.94 rows=10 width=154)
-> Index Scan using node_pkey on node n (cost=0.56..739571.11 rows=4874 width=154)
Filter: ((properties @> '{"slug": "wild-castles"}'::jsonb) AND ((node_type_id)::text = '2'::text))
字段上设置了GIN索引。
当我运行此查询时:
SELECT n.*
FROM node n
WHERE node_type_id = '2'
AND properties @> '{"slug":"wild-castles"}'::JSONB
OFFSET 0 LIMIT 10;
Limit (cost=93.77..127.10 rows=10 width=154)
-> Bitmap Heap Scan on node n (cost=93.77..16338.56 rows=4874 width=154)
Recheck Cond: (properties @> '{"slug": "wild-castles"}'::jsonb)
Filter: ((node_type_id)::text = '2'::text)
-> Bitmap Index Scan on node_ix02 (cost=0.00..92.55 rows=4874 width=0)
Index Cond: (properties @> '{"slug": "wild-castles"}'::jsonb)
在~5M行表上大约需要20秒才能得到答案。查看解释计划,我发现查询优化器首先按主键对表进行排序,然后按WHERE properties @> '{"slug":"wild-castles"}'::JSONB
字段进行过滤:
EXPLAIN SELECT n.*
FROM node n
WHERE properties @> '{"slug":"wild-castles"}'::JSONB
;
Bitmap Heap Scan on node n (cost=93.77..16326.38 rows=4874 width=154)
Recheck Cond: (properties @> '{"slug": "wild-castles"}'::jsonb)
-> Bitmap Index Scan on node_ix02 (cost=0.00..92.55 rows=4874 width=0)
Index Cond: (properties @> '{"slug": "wild-castles"}'::jsonb)
但是当我删除顺序时,我看到优化器使用索引按预期方式:
id
此外,简单exports.lp = function (str, strm) {
return function prependLog() {
var args = Array.from(arguments);
var hasNonWhitespace = args.some(function (a) {
var str = String(a);
return str.length > 0 && /\S/g.test(str);
});
if (hasNonWhitespace) {
strm.write(str);
}
args.forEach(function (s, i) {
String(s).split('\n').forEach(function (s, i) {
if (i < 1) {
strm.write(s + ' ');
}
else {
strm.write('\n' + str + s);
}
});
});
strm.write('\n');
};
};
的行为与预期相符:
const {lp} = require('log-prepend');
const fn = lp(' [foobar] ', process.stdout);
fn('\n');
fn();
fn();
fn('','','');
fn('log1', 'log2\n3',4,5 + '\n55');
fn('a','b','c');
所以我想我想知道为什么优化器不会先使用索引来过滤掉行,然后按 [foobar]
[foobar] log1 log2
[foobar] 34 5
[foobar] 55
[foobar] a b c
字段对它们进行排序?
答案 0 :(得分:1)
更改Planner Method Configuration并强制刨刀不要执行seqscan
例如
SET enable_seqscan = OFF;
SELECT n.*
FROM node n
WHERE node_type_id = '2'
AND properties @> '{"slug":"wild-castles"}'::JSONB
ORDER BY n.id ASC OFFSET 0 LIMIT 10;
答案 1 :(得分:1)
根据我的经验,您有时不得不欺骗查询规划器以使其表现良好,并且需要进行一些调整和摆弄......
我会尝试运行它来查看它的执行情况:
SELECT nn.* FROM (
SELECT n.*
FROM node n
WHERE node_type_id = '2'
AND properties @> '{"slug":"wild-castles"}'::JSONB
) nn
ORDER BY nn.id ASC OFFSET 0 LIMIT 10;