Key-set分页中JavaScript时间精度不足引发的PostgreSQL查询异常
Key-set分页中的时间精度匹配问题
在实现Key-set Pagination功能时遇到以下问题:从API获取的timestamp仅支持毫秒精度,这是JavaScript Date的固有精度限制导致的,但数据库(PostgreSQL v15)存储的时间精度更高,最终引发分页查询匹配异常。
数据库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);
排序规则
以下是按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 |
精度不匹配问题
由于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 |
临时方案:用date_trunc限制查询精度
这个方法能得到预期结果,但需要根据字段类型动态构建查询,可能存在性能问题,因此不想仅依赖此方案:
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 |
寻求替代方案
目前已知一种解决方案是在客户端与服务端之间传输bigint字符串,但希望在进行耗时改造前,找到其他更优的方案,恳请社区提供建议。
内容的提问来源于stack exchange,提问作者Bjørn Bråthen
相关产品推荐
相关产品推荐

