Postgresql:适用于(时间戳,字符串)的多列索引

时间:2018-04-27 14:13:34

标签: sql postgresql database-indexes

我的表中有时间戳字段(格式为 yyyy-MM-dd HH:mm:ss.SSS )(没有时区的时间戳)和非唯一字段(字符串格式) )。

考虑一个例子:
假设这是表用户(userId,userType,modifiedOn)。 userType是非唯一键,modifiedOn是没有时区的时间戳。

用户表在某些符合条件的标准上通过其他作业以20-40分钟的间隔进行更新。

userType可以是最大 200个不同的值,而用户表包含数百万个数据

我应该使用哪种类型的索引?

目前正在尝试

CREATE INDEX user_modifiedOn_userType_index on user USING btree(modifiedOn,userType);

注意
我正在这段时间之间进行修改,例如在04-04-APR-18 07:44:21'和' 06-APR-18 07:44:21'。
目前使用postgresql版本9.6以后将转移到10.3

但我怀疑

1)在multiColumn索引中,列的顺序有多少?

思想:modifiedOn将拥有数百万个不同的值,因此它应该首先出现,而userType几乎没有200个不同的值。

2)时间戳上的索引是否可达到小时或分钟?如果有可能那么它将对性能产生多大影响。

1 个答案:

答案 0 :(得分:0)

TL; DR:根据您最常见的查询,您应该在(user_type, modifiedon)上编制索引。如果省略第一列,索引将不是最佳的,但仍然有用。

尝试考虑数据在索引中的组织方式:实际上,它是一个排序列表,首先由第一个索引列排序,然后 - 在第一列的相等值的每组内 - 由第二个索引列排序

因此,如果您在(modifiedon, usertype)上编制索引,索引将与此类似:

 modifiedon |  usertype
------------+-------------
 2018-01-01 | basicuser
 2018-01-01 | normaluser
 2018-01-01 | superuser
 2018-01-01 | .........
 2018-01-02 | normaluser
 2018-01-02 | .........
 .......... | .........
 2018-04-29 | basicuser
 2018-04-29 | normaluser
 2018-04-29 | xpertuser

只有当您要查找的数据在索引中形成连续的条目块时,才能使用索引扫描。

现在,如果您的查询是

SELECT * FROM user WHERE modifiedon BETWEEN $1 AND $2 AND usertype = $3;

索引可以用于第一个条件,因为两个日期之间modifiedon的条目形成一个连续的索引条目块。但是,索引不能用于第二个条件,因为某个usertype的索引条目在第一个条件选择的块中不是彼此相邻的。

但是,如果您在(usertype, modifiedon)上有索引,它将如下所示:

 usertype   | modifiedon
------------+-------------
 basicuser  | 2018-01-01
 basicuser  | 2018-01-02
 basicuser  | ..........
 basicuser  | 2018-04-29
 normaluser | 2018-01-01
 normaluser | 2018-01-02
 normaluser | ..........
 normaluser | 2018-04-29
 .......... | ..........
 xpertuser  | 2018-03-01
 xpertuser  | ..........
 xpertuser  | 2018-04-29

很明显,与查询匹配的条目在索引中形成一个连续的条目块,因此可以将用于整个条件

因此,这个组合索引是查询的最佳索引。

然而,可能只有极少数usertype。然后第二个条件不是很有选择性,并且在索引中包含usertype列没有多大好处。事实上,它可能是有害的,因为它会使索引变大,这意味着在索引扫描期间会有更多工作,这样你就可以有效地失去这种方式。