Postgresql:适用于(时间戳,字符串)的多列索引
Posted
技术标签:
【中文标题】Postgresql:适用于(时间戳,字符串)的多列索引【英文标题】:Postgresql : Suitable multi column indexing for (timestamp,string) 【发布时间】:2018-04-27 14:13:34 【问题描述】:我有一个表,其中有时间戳字段(格式为 yyyy-MM-dd HH:mm:ss.SSS )(没有时区的时间戳)和一个非唯一字段(字符串格式) .
考虑一个例子: 假设这是表 User(userId,userType,modifiedOn)。 userType 是非唯一键,modifiedOn 是没有时区的时间戳。
用户表每隔 20 到 40 分钟会根据其他作业的某些符合条件的条件进行更新。
userType 可以是最大 200 个不同的值,而 User 表有数百万条数据。
我应该使用什么类型的索引?
目前我正在尝试
CREATE INDEX user_modifiedOn_userType_index on user USING btree(modifiedOn,userType);
注意: 我把这个时间范围放在'04-APR-18 07:44:21'和'06-APR-18 07:44:21'之间。 目前使用postgresql 9.6 版本以后会换到10.3
但我有疑问:
1) 在多列索引中,列的顺序有多重要?
想法:modifiedOn 将有数百万个不同的值,所以它应该排在第一位,而 userType 几乎没有 200 个不同的值。
2) 时间戳索引是否可以长达一小时或一分钟?如果可能,那么它将对性能产生多大影响。
【问题讨论】:
不相关,但是:时间戳列没有“格式” 索引策略取决于查询,而不是表。经验法则是:先为相等索引,然后为范围。 @a_horse_with_no_name 但是 userType 最多有 200 个不同的值,所以我认为 modifiedOn 应该排在第一位。我的查询是 Select * from user where modifiedOn between ?和 ?和用户类型 = ?或 Select * from user where modifiedOn >= ?. 再次重申:这取决于您使用的 查询。 @a_horse_with_no_name 这个是关键的 Select * from user where modifiedOn between ?和 ?和 userType = ?. 【参考方案1】: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
s 可能只有极少数。那么第二个条件选择性不是很高,在索引中包含usertype
列并没有太大的好处。事实上,它可能是有害的,因为它会使索引变大,这意味着在索引扫描期间需要做更多的工作,因此您可能会失去这种方式。
【讨论】:
你能提供任何参考来证明你的观点吗? (user_type, modifiedon) 上的索引为什么不是这个命令 (modifiedon, user_type) ?在上面与“a_horse_with_no_name”的讨论中,以了解有关我的查询的更多信息。 足够公平的请求。我已经扩展了答案,大大增加了解释。如果您需要参考,简单的网络搜索应该会找到大量信息。以上是关于Postgresql:适用于(时间戳,字符串)的多列索引的主要内容,如果未能解决你的问题,请参考以下文章
正则表达式从 postgresql 中的时间戳字符串中间删除“-”
PostgreSQL:将字符串转换为没有时区的时间戳以更改时间日期时,我得到了意想不到的结果