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

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

所以这个组合索引是查询的最佳索引。

但是,usertypes 可能只有极少数。那么第二个条件选择性不是很高,在索引中包含usertype列并没有太大的好处。事实上,它可能是有害的,因为它会使索引变大,这意味着在索引扫描期间需要做更多的工作,因此您可能会失去这种方式。

【讨论】:

你能提供任何参考来证明你的观点吗? (user_type, modifiedon) 上的索引为什么不是这个命令 (modifiedon, user_type) ?在上面与“a_horse_with_no_name”的讨论中,以了解有关我的查询的更多信息。 足够公平的请求。我已经扩展了答案,大大增加了解释。如果您需要参考,简单的网络搜索应该会找到大量信息。

以上是关于Postgresql:适用于(时间戳,字符串)的多列索引的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式从 postgresql 中的时间戳字符串中间删除“-”

PostgreSQL:将字符串转换为没有时区的时间戳以更改时间日期时,我得到了意想不到的结果

Postgresql 常用命令

适用于 Android 的书签时间戳视频播放器

Postgresql时间戳long转日期,转字符串,转timestamp,日期转换错误定位及解决

JasperReports 未将 postgresql 时间戳转换为简单日期