【发布时间】:2020-01-24 17:38:14
【问题描述】:
上下文:
我有一个test 表:
=> \d+ test
Table "public.test"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
---------------+------------------------+-----------+----------+---------+----------+--------
------+-------------
id | character varying(255) | | | | extended |
|
configuration | jsonb | | | | extended |
|
configuration 列包含“定义明确”的 json,其中有一个名为 source_url 的键(跳过其他不相关的键)。 configuration 列的示例值为:
{
"source_url": "https://<resource-address>?Signature=R1UzTGphWEhrTTFFZnc0Q4qkGRxkA5%2BHFZSfx3vNEvRsrlDcHdntArfHwkWiT7Qxi%2BWVJ4DbHJeFp3GpbS%2Bcb1H3r1PXPkfKB7Fjr6tFRCetDWAOtwrDrVOkR9G1m7iOePdi1RW%2Fn1LKE7MzQUImpkcZXkpHTUgzXpE3TPgoeVtVOXXt3qQBARpdSixzDU8dW%2FcftEkMDVuj4B%2Bwiecf6st21MjBPjzD4GNVA%2F6bgvKA6ExrdYmM5S6TYm1lz2e6juk81%2Fk4eDecUtjfOj9ekZiGJVMyrD5Tyw%2FTWOrfUB2VM1uw1PFT2Gqet87jNRDAtiIrJiw1lfB7Od1AwNxIk0Rqkrju8jWxmQhvb1BJLV%2BoRH56OHdm5nHXFmQdldVpyagQ8bQXoKmYmZPuxQb6t9FAyovGMav3aMsxWqIuKTxLzjB89XmgwBTxZSv5E9bkWUbom2%2BWq4O3%2BCrVxYwsqg%3D%3D&Expires-At=1569340020&Issued-At=1568293200"
.
.
}
URL 包含查询参数Expires-At
问题:
有一个每 24 小时运行一次的计划作业。这项工作应该找到所有已过期/即将过期的记录(然后对其进行处理)。
解决方案:
我有这个查询来完成我的工作:
select * from test where to_timestamp(split_part(split_part(configuration->>'source_url', 'Expires-At=', 2), '&', 1)::bigint) <= now() + interval '24 hours';
说明:
- 查询首先在
Expires-At=处拆分source_url并选择其右侧的部分,然后在&上拆分结果字符串并选择其左侧部分,从而获得准确的纪元时间需要text - 当
Expires-At是source_url中的最后一个查询参数时,相同的查询也适用于极端情况 - 一旦提取纪元时间为
text,它首先将其转换为bigint,然后将其转换为Postgres时间戳,然后比较该时间戳是否小于或等于时间24距离now()几小时车程 - 所有符合上述条件的行都被选中
因此,最后,在每次运行中,调度程序都会刷新所有将在接下来的 24 小时内过期的 url(包括那些已经过期的)
问题:
- 虽然这解决了我的问题,但我真的不喜欢这个解决方案。这有很多我觉得不干净的字符串操作。有没有更清洁的方法来做到这一点?
- 如果我们“不得不”采用上述解决方案,我们甚至可以使用索引来进行这种查询吗?我知道函数
lower()、upper()extra 可以被索引,但我真的想不出任何可以索引这个查询的方法。
替代方案:
除非有一个真正干净的解决方案,否则我会选择这个:
- 我会在
configurationjson 中引入一个名为expires_at的新键,确保每次插入一行时都会填充正确的值。 - 然后直接查询这个新增的字段(在
configuration列上有索引)。
我承认这样我重复了Expires-At 的信息,但是在我能想到的所有可能的解决方案中,这是我认为最干净的一个。
还有比这更好的方法吗?
编辑:
更新了查询以使用带有正则表达式的substring() 而不是内部split_part():
select * from test where to_timestamp(split_part(substring(configuration->>'source_url' from 'Expires-At=\d+'), '=', 2)::bigint) <= now() + interval '24 hours';
【问题讨论】:
标签: sql postgresql indexing split jsonb