我的表中有时间戳字段(格式为 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)时间戳上的索引是否可达到小时或分钟?如果有可能那么它将对性能产生多大影响。
答案 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
列没有多大好处。事实上,它可能是有害的,因为它会使索引变大,这意味着在索引扫描期间会有更多工作,这样你就可以有效地失去这种方式。