我的键集分页功能遇到了一个问题,因为我接收的时间戳值被限制为毫秒,导致与数据库期望的精度不匹配.这种限制源于JavaScript Date实现中固有的精度不足.不幸的是,我无法控制这个方面,因为这个值是从API端点获得的.虽然一种解决方法涉及向客户端传输bigint字符串值以及从客户端传输bigint字符串值,但在诉诸可能耗时的更改之前,我对探索这个问题的替代解决方案感兴趣.

Schema (PostgreSQL v15)

CREATE TABLE IF NOT EXISTS public.activities
(
    id uuid NOT NULL DEFAULT gen_random_uuid(),    
    created_at timestamp with time zone DEFAULT now(),
    PRIMARY KEY (id)
);

CREATE INDEX activities_created_at_id ON activities (created_at, id);

Ordering

下面是按created_at asc,id asc排序的表内容

select id, created_at from activities order by created_at asc, id asc;
id created_at
e34d5557-43d7-4f81-802b-791c213ea5cb 2024-03-14T07:23:56.474123Z
ea7e9cad-89f2-4610-898f-62a04e8b5331 2024-03-14T07:23:56.474123Z
0cf727a8-5efc-454b-ba1b-ea301e2b1a82 2024-03-14T07:23:56.474222Z
10f1dd9b-2cd8-40bb-a199-2d9c922d07b1 2024-03-14T07:23:56.474222Z
3c00c38e-45b9-4c3c-9d05-fc1ca2177dbe 2024-03-14T07:23:56.474222Z
ac31e591-d4ea-4ef5-956a-c07bd043d9ea 2024-03-14T07:23:56.474222Z
b9b33ca5-2cd1-490b-a6be-d28784f75b2a 2024-03-14T07:23:56.474222Z
bc9763d0-6d24-4fbf-bc23-7eff1589280a 2024-03-14T07:23:56.474222Z
c442f6ea-61bf-42d4-aa85-4eab1d95f569 2024-03-14T07:23:56.474222Z
ded826f7-65f0-4d23-9366-049823ba49ec 2024-03-14T07:23:56.474222Z

Issue with Significant Digits

与数据库中存储的数据相比,提供的输入缺乏精确性.由于JavaScript在支持超过毫秒的精度方面的限制,以下查询检索所有活动:

select id, created_at from activities
where (created_at, id) > ('2024-03-14T07:23:56.474Z', 'b9b33ca5-2cd1-490b-a6be-d28784f75b2a')
order by created_at asc, id asc;
id created_at
e34d5557-43d7-4f81-802b-791c213ea5cb 2024-03-14T07:23:56.474Z
ea7e9cad-89f2-4610-898f-62a04e8b5331 2024-03-14T07:23:56.474Z
0cf727a8-5efc-454b-ba1b-ea301e2b1a82 2024-03-14T07:23:56.474Z
10f1dd9b-2cd8-40bb-a199-2d9c922d07b1 2024-03-14T07:23:56.474Z
3c00c38e-45b9-4c3c-9d05-fc1ca2177dbe 2024-03-14T07:23:56.474Z
ac31e591-d4ea-4ef5-956a-c07bd043d9ea 2024-03-14T07:23:56.474Z
b9b33ca5-2cd1-490b-a6be-d28784f75b2a 2024-03-14T07:23:56.474Z
bc9763d0-6d24-4fbf-bc23-7eff1589280a 2024-03-14T07:23:56.474Z
c442f6ea-61bf-42d4-aa85-4eab1d95f569 2024-03-14T07:23:56.474Z
ded826f7-65f0-4d23-9366-049823ba49ec 2024-03-14T07:23:56.474Z

Using 100 to Cap Precision When Querying

在达到预期结果的同时,我不太愿意只在查询中处理这个问题.这种方法需要根据字段类型动态调整查询构造,这可能会带来性能方面的问题:

select id, created_at from activities
where (date_trunc('milliseconds', created_at::timestamptz), id) < (date_trunc('milliseconds', '2024-03-14T07:23:56.474Z'::timestamptz), 'b9b33ca5-2cd1-490b-a6be-d28784f75b2a')
order by created_at desc, id desc;
id created_at
ac31e591-d4ea-4ef5-956a-c07bd043d9ea 2024-03-14T07:23:56.474Z
3c00c38e-45b9-4c3c-9d05-fc1ca2177dbe 2024-03-14T07:23:56.474Z
10f1dd9b-2cd8-40bb-a199-2d9c922d07b1 2024-03-14T07:23:56.474Z
0cf727a8-5efc-454b-ba1b-ea301e2b1a82 2024-03-14T07:23:56.474Z

考虑到这些选项,我愿意听取社区的建议和见解,以有效地解决这个分页挑战.

View on DB Fiddle

推荐答案

如果PostgreSQL微秒分辨率只是阻碍了它,你不需要使用它:it's customisable.

timetimestampinterval接受一个可选的精度值103,它指定了秒字段中保留的小数位数.默认情况下,精度没有明确限制.103的允许范围是从0到6.

您可以在表中所有现有行和future 行中就地alter列类型,这将简单地round字段中的最后3位数字:demo

alter table activities alter column created_at type timestamptz(3);

select id, 
       to_char(created_at,
               'YYYY-MM-DD"T"HH24:MI:SS.USTZ'),
       to_char('2024-03-14T07:23:56.474Z'::timestamptz,
               'YYYY-MM-DD"T"HH24:MI:SS.USTZ') target
from activities
where (created_at, id) 
    > ('2024-03-14T07:23:56.474Z', 'b9b33ca5-2cd1-490b-a6be-d28784f75b2a')
order by created_at asc, id asc;
id to_char target
bc9763d0-6d24-4fbf-bc23-7eff1589280a 2024-03-14T07:23:56.474000UTC 2024-03-14T07:23:56.474000UTC
c442f6ea-61bf-42d4-aa85-4eab1d95f569 2024-03-14T07:23:56.474000UTC 2024-03-14T07:23:56.474000UTC
ded826f7-65f0-4d23-9366-049823ba49ec 2024-03-14T07:23:56.474000UTC 2024-03-14T07:23:56.474000UTC
e34d5557-43d7-4f81-802b-791c213ea5cb 2024-03-14T07:23:56.474000UTC 2024-03-14T07:23:56.474000UTC
ea7e9cad-89f2-4610-898f-62a04e8b5331 2024-03-14T07:23:56.474000UTC 2024-03-14T07:23:56.474000UTC

较低分辨率列也可以基于原始列为generated,以防微秒在其他地方是有用的或可能在某一点上变得有用:

alter table activities 
  add column created_at_mili_precise timestamptz(3) 
    generated always as (created_at::timestamptz(3)) stored;

Typescript相关问答推荐

angular 17独立使用多个组件(例如两个组件)

有没有可能使用redux工具包的中间件同时监听状态的变化和操作

使用带有RxJS主题的服务在Angular中的组件之间传递数据

SortKey类型不起作用,尽管它使用的单个类型工作正常<>'

如何使用泛型类型访问对象

如何在TypeScrip面向对象程序设计中用方法/属性有条件地扩展类

带switch 的函数的返回类型的类型缩小

TypeScrip界面属性依赖于以前的属性-针对多种可能情况的简明解决方案

类型脚本返回的类型包含无意义的泛型类型名称

对于始终仅在不是对象属性时才抛出的函数,返回Never

尽管对象的类型已声明,但未解析的变量<;变量

在Mac和Windows上运行的Web应用程序出现这种对齐差异的原因是什么?(ReactNative)

使用泛型识别对象值类型

是否可以通过映射类型将函数参数约束为预定义类型?

使用ngfor循环时,数据未绑定到表

如何通过转换器类继承使用多态将对象从一种类型转换为另一种类型

字符串文字联合的分布式条件类型

如何创建一个将嵌套类属性的点表示法生成为字符串文字的类型?

Karma Angular Unit测试如何创建未解析的promise并在单个测试中解决它,以判断当时的代码是否只在解决后运行

基于泛型类型的条件类型,具有条目属性判断