json 字段检查和字段范围查询的最佳索引是什么
What's the best index for a json fields checking and fields range queries
假设我们有以下 table:
我有以下对象:
struct Tick = {
country string
region string
type string
spec map string -> int # {v1: n1, v2:n2}
t timestamp
}
我想将此对象存储在 Posgresql 9.4 中。将有数百万个。
90% 的查询将涉及:
type
country
/ region
的组合(两者,一个或 none)
t
范围(大部分只是 t > tx
)
以上所有查询组合都是均匀分布的。
然后大约 5% 将额外涉及检查规范属性:存在或范围。
在 Postgresql 9.4 中编码此类对象的最佳方法是什么?应该创建哪个索引?
一些想法:
- 将所有字段编码为单个字符串并进行正则表达式查询。例如:
encoded = "type;country;v1:n1;v2:n2"
。那么,是否可以创建一个复合索引 (t, encoded)
,它允许对 t
进行范围查询,对 encoded
进行正则表达式查询?在这种方法中,我们取消了索引中的规范范围检查,
- 编码
jsonb
中的所有内容。那么,是否可以对某些jsonb属性进行索引范围查询?
[编辑]
广告。 1. 可以将这些值放在 table (tab = {type, country, v1+n1, ...}
) 中并创建 gin 索引:gin (t timestamp_ops, tab _text_ops)
使用 btree_gini 扩展名,而不是将这些值编码为单个字符串。
保持简单。使用常规 table 和复合索引。
我会看类似的东西:
CREATE OR REPLACE TABLE blah (
country text,
region text,
type text,
spec json,
t timestamp not null
);
那里没有明显的候选键,因此您可能还需要一个合成主键。
然后在数据上有一个或多个复合索引,比如
CREATE INDEX blah_t_country_region_idx
ON blah(t, type, country, region);
列的顺序很重要;如果所有查询都使用所有列,它应该从最多到最少选择。否则,您应该更愿意将最常查询使用的列放在最前面。
您可以创建多个索引。 PostgreSQL 有时也可以为单个查询组合多个索引。
请记住,每个索引都有成本 insert/update 并且还使用磁盘 space。
一个选项可能是:
CREATE INDEX blah_t_country_region_idx
ON blah(t, type);
然后在 country
和 region
上分离索引。或者多个复合索引,一个t+type+country,一个t+type+region,一个both。这完全取决于您愿意支付多少磁盘 space 和 I/O 成本,以及您的确切查询模式。
在不知道查询模式和有一些查询 explain
数据的情况下提出更详细的策略是不切实际的。
顺便说一句,根据数据源等,您可能希望将国家和地区外键放入查找 table 中,而不是存储文字字符串。
假设我们有以下 table:
我有以下对象:
struct Tick = {
country string
region string
type string
spec map string -> int # {v1: n1, v2:n2}
t timestamp
}
我想将此对象存储在 Posgresql 9.4 中。将有数百万个。 90% 的查询将涉及:
type
country
/region
的组合(两者,一个或 none)t
范围(大部分只是t > tx
)
以上所有查询组合都是均匀分布的。 然后大约 5% 将额外涉及检查规范属性:存在或范围。
在 Postgresql 9.4 中编码此类对象的最佳方法是什么?应该创建哪个索引?
一些想法:
- 将所有字段编码为单个字符串并进行正则表达式查询。例如:
encoded = "type;country;v1:n1;v2:n2"
。那么,是否可以创建一个复合索引(t, encoded)
,它允许对t
进行范围查询,对encoded
进行正则表达式查询?在这种方法中,我们取消了索引中的规范范围检查, - 编码
jsonb
中的所有内容。那么,是否可以对某些jsonb属性进行索引范围查询?
[编辑]
广告。 1. 可以将这些值放在 table (tab = {type, country, v1+n1, ...}
) 中并创建 gin 索引:gin (t timestamp_ops, tab _text_ops)
使用 btree_gini 扩展名,而不是将这些值编码为单个字符串。
保持简单。使用常规 table 和复合索引。
我会看类似的东西:
CREATE OR REPLACE TABLE blah (
country text,
region text,
type text,
spec json,
t timestamp not null
);
那里没有明显的候选键,因此您可能还需要一个合成主键。
然后在数据上有一个或多个复合索引,比如
CREATE INDEX blah_t_country_region_idx
ON blah(t, type, country, region);
列的顺序很重要;如果所有查询都使用所有列,它应该从最多到最少选择。否则,您应该更愿意将最常查询使用的列放在最前面。
您可以创建多个索引。 PostgreSQL 有时也可以为单个查询组合多个索引。
请记住,每个索引都有成本 insert/update 并且还使用磁盘 space。
一个选项可能是:
CREATE INDEX blah_t_country_region_idx
ON blah(t, type);
然后在 country
和 region
上分离索引。或者多个复合索引,一个t+type+country,一个t+type+region,一个both。这完全取决于您愿意支付多少磁盘 space 和 I/O 成本,以及您的确切查询模式。
在不知道查询模式和有一些查询 explain
数据的情况下提出更详细的策略是不切实际的。
顺便说一句,根据数据源等,您可能希望将国家和地区外键放入查找 table 中,而不是存储文字字符串。