如何通过DynamoDB全局二级索引查询指定账号近30天数据
DynamoDB 基于GSI3查询指定账号近30天数据实现方案
你的GSI3设计本身就适配这个查询场景:分区键绑定账号ID,排序键存epoch时间戳,直接用Query接口就能按范围拉取,不需要全表扫描,性能和成本都可控。
前置准备:计算时间范围
先算准查询的时间边界,核心是和表中存储的GSI3SK时间单位完全对齐:
- 结束时间戳:取当前时间的epoch值,提前确认表中存的是秒级还是毫秒级,单位错了100%查不准
- 起始时间戳:结束时间戳减去30天对应的时间长度,秒级的话减
2592000(30243600),毫秒级的话减2592000000
举个实际例子:如果当前秒级时间戳是1727740800,30天前的起始时间戳就是1725148800。
核心查询参数构造
调用Query接口时必须指定查询GSI3,不能默认查主表,核心参数配置如下:
IndexName:固定填GSI3KeyConditionExpression:包含两个条件- 分区键等值匹配:
GSI3pk = :accountPk - 排序键范围匹配:
GSI3SK BETWEEN :startTs AND :endTs
- 分区键等值匹配:
ExpressionAttributeValues:绑定对应参数值:accountPk:值为ACT#234,严格匹配GSI3分区键的前缀规则:startTs:前面算出的30天前时间戳:endTs:当前时间戳
- 可选配置:如果需要最新数据排在前面,加参数
ScanIndexForward=False,默认是按时间从早到晚正序返回;如果不需要全字段返回,加ProjectionExpression指定需要的字段,能省读容量。
参考代码(Python boto3)
import boto3 import time # 初始化表客户端,替换成你自己的表名 dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('替换成你的业务表名') # 计算时间范围,这里示例用秒级时间戳,毫秒的话把时间戳乘1000即可 end_ts = int(time.time()) start_ts = end_ts - 30 * 24 * 3600 result_items = [] query_kwargs = { 'IndexName': 'GSI3', 'KeyConditionExpression': 'GSI3pk = :acc_pk AND GSI3SK BETWEEN :start AND :end', 'ExpressionAttributeValues': { ':acc_pk': 'ACT#234', ':start': start_ts, ':end': end_ts }, 'ScanIndexForward': False # 按时间倒序返回,不需要可以删掉 } # 循环处理分页,DynamoDB单次查询最多返回1MB数据 while True: resp = table.query(**query_kwargs) result_items.extend(resp['Items']) # 没有更多数据就退出循环 if 'LastEvaluatedKey' not in resp: break query_kwargs['ExclusiveStartKey'] = resp['LastEvaluatedKey'] # 最终result_items就是账号234近30天的所有记录
常见踩坑提醒
- 别搞混索引和主表的字段规则:主表SK带
AYT#前缀,但GSI3SK是纯时间戳,传值的时候不要加多余前缀 - 别漏写
IndexName参数:不指定的话默认查主表,主表分区键是用户和账号拼接的格式,传ACT#234会查不到任何数据 - 数据量太大的场景:如果单账号30天数据超过1000条或者1MB,一定要做分页处理,不然会丢数据
- 时间单位校验:写代码前先翻一条表里的真实数据,确认GSI3SK是秒还是毫秒,别靠猜
内容的提问来源于stack exchange,提问作者newbiee
相关产品推荐
相关产品推荐

