第一章:DynamoDB 基础概念
1.1 什么是 DynamoDB
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| DynamoDB | Amazon 提供的完全托管、高可用、低延迟的 NoSQL 键值与文档数据库服务,支持自动扩展、备份、加密和流式处理。 | 不需要用户管理服务器、分片或复制;适用于高并发、低延迟场景。 |
| 托管服务 | AWS 负责底层基础设施、故障恢复、软件更新和扩展。 | 用户无法直接访问底层存储节点,仅通过 API 或 CLI 操作数据。 |
| 无服务器架构 | 自动根据负载调整资源,按实际使用量计费(尤其在按需模式下)。 | 需合理设计表结构以避免热点分区,否则可能影响性能。 |
1.2 核心术语:表、项、属性、主键(分区键/排序键)
| 术语 | 说明 | 注意事项 |
|---|---|---|
| 表(Table) | DynamoDB 中的顶层容器,用于存储一组具有相同结构的数据项。每个表必须有唯一名称。 | 表名在 AWS 账户和区域范围内必须全局唯一。 |
| 项(Item) | 表中的一条记录,类似于关系数据库中的”行”。由多个属性组成。 | 单个项最大为 400 KB。 |
| 属性(Attribute) | 项中的字段,由名称和值组成,值可为标量、集合或嵌套文档。 | 属性无需预定义(除主键外),支持动态 schema。 |
| 分区键(Partition Key) | 主键的一部分,决定数据在哪个物理分区存储。DynamoDB 使用哈希函数对分区键取模。 | 分区键选择不当会导致数据分布不均(热点问题)。 |
| 排序键(Sort Key / Range Key) | 可选的主键第二部分,用于在同一分区键下对项进行排序。 | 必须与分区键一起使用;支持范围查询(如 >、BETWEEN)。 |
| 复合主键(Composite Primary Key) | 由分区键 + 排序键组成的主键。 | 允许一个分区键对应多个项,提升查询灵活性。 |
1.3 数据模型与数据类型
| 数据类型类别 | 支持的具体类型 | 说明 | 注意事项 |
|---|---|---|---|
| 标量类型(Scalar) | String (S)、Number (N)、Binary (B)、Boolean (BOOL)、Null (NULL) | 表示单个值。Number 实际存储为字符串形式以避免精度问题。 | Number 类型在 CLI 中需用字符串表示(如 "123"),但支持数值比较。 |
| 集合类型(Set) | String Set (SS)、Number Set (NS)、Binary Set (BS) | 无序、不重复的同类型元素集合。 | 所有元素必须为同一类型;不能嵌套集合。 |
| 文档类型(Document) | List (L)、Map (M) | List 是有序数组,Map 是键值对对象。支持嵌套。 | 最大嵌套深度为 32 层;常用于 JSON-like 结构。 |
示例项结构(JSON 表示):
{
"UserId": {"S": "user123"},
"Scores": {"NS": ["95", "87", "92"]},
"Profile": {
"M": {
"Name": {"S": "Alice"},
"Active": {"BOOL": true}
}
},
"Tags": {"L": [{"S": "premium"}, {"S": "beta"}]}
}
1.4 一致性模型:强一致 vs 最终一致读
| 读取类型 | 说明 | 适用场景 | 注意事项 |
|---|---|---|---|
| 强一致读(Strongly Consistent Read) | 返回最新写入的数据,保证读取结果反映所有已完成的写操作。 | 金融交易、库存扣减等要求数据绝对准确的场景。 | 仅在主副本上执行,延迟略高;不支持跨区域复制表的强一致读。 |
| 最终一致读(Eventually Consistent Read) | 默认读取方式,可能返回稍旧的数据,但通常在 1 秒内达到一致。 | 用户资料展示、日志分析等容忍短暂延迟的场景。 | 性能更好、吞吐更高;免费(相比强一致读消耗更少读容量单位)。 |
| 读容量单位(RCU)消耗 | 强一致读:1 RCU = 读取 4 KB 数据;最终一致读:1 RCU = 读取 8 KB 数据。 | — | 按需模式下仍会计费,但无容量限制。 |
1.5 容量模式:预置容量 vs 按需容量
| 容量模式 | 说明 | 适用场景 | 注意事项 |
|---|---|---|---|
| 预置容量模式(Provisioned Capacity) | 用户预先指定每秒读写容量单位(RCU/WCU),DynamoDB 按此分配资源。 | 负载稳定、可预测的生产系统;成本敏感且流量平稳的应用。 | 若超过预置容量会触发限流(Throttling);可启用自动扩缩容(Auto Scaling)。 |
| 按需容量模式(On-Demand Capacity) | 无需预设容量,DynamoDB 自动处理任意规模的请求,按实际请求次数计费。 | 流量波动大、不可预测的初创项目或测试环境;突发流量场景。 | 成本在高吞吐时可能显著高于预置模式;适合每月请求 < 10 亿次的场景。 |
| 切换限制 | 表创建后可在两种模式间切换,但有冷却时间(通常 24 小时内只能切换一次)。 | — | 切换期间表仍可读写,但建议避开业务高峰期。 |
第二章:DynamoDB 表结构设计
2.1 主键设计原则
| 原则名称 | 说明 | 注意事项 |
|---|---|---|
| 唯一性 | 主键(分区键或分区键+排序键)必须唯一标识表中的每一项。 | 重复主键会导致新项覆盖旧项。 |
| 高基数(High Cardinality) | 分区键应具有大量不同值,确保数据均匀分布到多个物理分区。 | 低基数键(如 status="active")易导致热点,限制吞吐扩展。 |
| 查询驱动设计 | 主键结构应围绕应用最频繁的查询模式设计,而非模仿关系模型。 | 避免”为存储而设计”,应”为访问而设计”。 |
| 避免单调递增键 | 如使用时间戳或自增 ID 作为分区键,会导致所有写入集中到最新分区。 | 可通过添加随机前缀(如 hash(time) + time)打散写入。 |
| 稳定性 | 主键一旦确定,无法修改(需重建表)。 | 设计阶段需充分评审业务查询路径。 |
2.2 使用排序键实现多维查询
| 功能 | 说明 | 操作支持 | 注意事项 |
|---|---|---|---|
| 范围查询 | 在相同分区键下,按排序键进行 >、<、BETWEEN、BEGINS_WITH 等操作。 | 支持 Query API 中的 KeyConditionExpression。 | 排序键必须是 Number、String 或 Binary 类型。 |
| 多条件组织 | 将多个维度编码到排序键中(如 "USER#123"、"ORDER#20250405"),实现单一分区键下的多类型数据共存。 | 配合 BEGINS_WITH 实现类型过滤。 | 需统一命名规范,避免冲突;可读性可能下降。 |
| 时间序列存储 | 分区键为实体 ID(如 userId),排序键为时间戳,便于获取用户最近 N 条记录。 | Query + ScanIndexForward=false 可倒序获取最新数据。 | 单个分区键下项数不宜过多(建议 < 10GB 数据)。 |
| 复合排序键 | 将多个字段拼接为排序键(如 "STATUS#ACTIVE#TIMESTAMP#1712345678"),支持多维过滤。 | 需配合 FilterExpression 进一步筛选非前缀部分。 | 拼接顺序影响查询能力;前缀匹配才有效。 |
示例排序键设计:
- 分区键:
USER#alice - 排序键:
ORDER#20250405#12345 - 查询:
KeyConditionExpression="PK = :pk AND SK BEGINS_WITH :sk"
其中 :pk = "USER#alice", :sk = "ORDER#20250405"
2.3 全局二级索引(GSI)
| 概念/参数 | 说明 | 注意事项 |
|---|---|---|
| 定义 | GSI 是独立于主表的索引,拥有自己的分区键和可选排序键,可不同于主键。 | 一个表最多创建 20 个 GSI。 |
| 投影属性(Projection) | 指定哪些属性从主表复制到 GSI。可选 KEYS_ONLY、INCLUDE(指定属性)、ALL。 | ALL 投影会增加存储成本和写入延迟。 |
| 一致性 | GSI 为最终一致,写入主表后可能有短暂延迟才反映在 GSI 中。 | 不支持强一致读;不适合实时一致性要求高的场景。 |
| 容量模式 | GSI 可独立选择预置或按需容量(与主表无关)。 | 若主表为按需,GSI 默认也为按需,但可单独配置。 |
| 查询能力 | 可对 GSI 执行 Query 和 Scan,如同独立表。 | GSI 的分区键也需高基数,避免热点。 |
| 写入成本 | 主表写入会同步写入所有 GSI,消耗额外 WCU。 | 删除项时也会触发 GSI 删除,计入写入成本。 |
CLI 创建 GSI 示例(片段):
--global-secondary-index-updates \
'[
{
"Create": {
"IndexName": "StatusIndex",
"KeySchema": [
{"AttributeName": "status", "KeyType": "HASH"},
{"AttributeName": "createdAt", "KeyType": "RANGE"}
],
"Projection": {"ProjectionType": "ALL"},
"ProvisionedThroughput": {"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}
}
}
]'
2.4 本地二级索引(LSI)
| 概念/参数 | 说明 | 注意事项 |
|---|---|---|
| 定义 | LSI 与主表共享相同分区键,但使用不同的排序键,用于在同一分区内提供替代排序视图。 | 仅在创建表时定义,无法后续添加。 |
| 数量限制 | 每个表最多 5 个 LSI(包括主表排序键本身)。 | 主表若无排序键,则不能创建 LSI。 |
| 投影 | 必须为 ALL(即 LSI 包含主表所有属性)。 | 无法选择性投影,存储开销固定。 |
| 一致性 | LSI 支持强一致读(因与主表同分区)。 | 适合需要强一致性的辅助排序查询。 |
| 容量共享 | LSI 与主表共享 RCU/WCU,不单独计费。 | 查询 LSI 消耗主表的读写容量。 |
| 适用场景 | 同一实体需按不同维度排序(如按时间、评分、状态)。 | 不适用于跨分区查询。 |
示例:主键 (userId, timestamp),LSI 排序键为 score,可查询某用户(userId)下按 score 排序的项。
2.5 单表设计 vs 多表设计
| 对比维度 | 单表设计(Single-Table Design) | 多表设计(Multi-Table Design) |
|---|---|---|
| 核心思想 | 将多种实体类型(如 User、Order、Product)存储在同一张 DynamoDB 表中,通过复合主键区分。 | 每种实体类型对应一张独立表,结构清晰。 |
| 查询效率 | 通过精心设计 PK/SK,可在一次 Query 中获取关联数据(如用户及其订单)。 | 关联查询需多次请求(如先查用户,再查其订单表)。 |
| 索引成本 | 减少 GSI 数量,降低存储与写入开销。 | 每张表可能需独立 GSI,总成本更高。 |
| 开发复杂度 | 应用层需处理数据类型识别、属性映射、反序列化逻辑。 | 逻辑简单,易于理解和维护。 |
| 适用团队 | 熟悉 DynamoDB 高级模式、追求极致性能与成本优化的团队。 | 初学者、快速原型开发、或业务模型高度规范化场景。 |
| AWS 官方建议 | 适用于复杂查询模式且能接受设计复杂性的场景。 | 对于简单 CRUD 或微服务隔离场景更合适。 |
| 注意事项 | 需统一命名空间(如 PK = "USER#alice", SK = "PROFILE");测试难度高。 | 表数量多可能导致 IAM 策略、监控、备份管理复杂化。 |
单表示例结构:
| PK | SK | Type | Name | Total |
|---|---|---|---|---|
USER#alice | PROFILE | User | Alice | |
USER#alice | ORDER#1001 | Order | 99.99 | |
ORDER#1001 | ITEM#A | Item | Laptop |
第三章:DynamoDB 基本操作(AWS CLI)
3.1 配置 AWS CLI 环境
| 步骤名称 | 操作细节 | 注意事项 |
|---|---|---|
| 安装 AWS CLI | 执行 curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip",然后运行 unzip awscliv2.zip && sudo ./aws/install(Linux 示例) | 支持 Windows、macOS、Linux;需 Python 3.7+(v2 版本内置 Python) |
| 配置凭证 | 运行 aws configure,依次输入 Access Key ID、Secret Access Key、默认区域(如 us-east-1)、输出格式(如 json) | 凭证需具备 DynamoDB 操作权限(通过 IAM 策略授权) |
| 验证配置 | 执行 aws sts get-caller-identity 查看当前身份 | 若返回错误,检查网络、凭证或 IAM 权限 |
| 设置默认区域 | 可通过环境变量 AWS_DEFAULT_REGION=us-west-2 覆盖配置文件中的区域 | DynamoDB 表是区域级资源,操作前必须指定正确区域 |
| 使用临时凭证(可选) | 通过 aws configure --profile dev 创建多配置文件,使用时加 --profile dev 参数 | 适用于多账号或角色切换场景 |
3.2 创建表(create-table)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| create-table | aws dynamodb create-table \ --table-name name \ --attribute-definitions AttributeName=name,AttributeType=type [...] \ --key-schema AttributeName=name,KeyType=HASH/RANGE [...] \ [--global-secondary-indexes ...] \ [--billing-mode PROVISIONED | PAY_PER_REQUEST] \ [--provisioned-throughput ReadCapacityUnits=n,WriteCapacityUnits=n] | 创建新 DynamoDB 表 | 见下方简单主键表示例 | 表名在区域内唯一;AttributeDefinitions 必须包含所有主键和索引键属性;若使用预置模式,必须提供 --provisioned-throughput |
| 带排序键和 GSI 的创建 | 同上,增加排序键和 GSI 定义 | 创建复合主键表及索引 | 见下方复合主键表示例 | GSI 定义需为 JSON 字符串;属性类型 S=String, N=Number, B=Binary;创建后表状态为 CREATING,需等待变为 ACTIVE |
简单主键表示例:
aws dynamodb create-table \
--table-name Users \
--attribute-definitions \
AttributeName=UserId,AttributeType=S \
--key-schema \
AttributeName=UserId,KeyType=HASH \
--billing-mode PAY_PER_REQUEST
带排序键和 GSI 示例:
aws dynamodb create-table \
--table-name Orders \
--attribute-definitions \
AttributeName=CustomerId,AttributeType=S \
AttributeName=OrderId,AttributeType=S \
AttributeName=Status,AttributeType=S \
--key-schema \
AttributeName=CustomerId,KeyType=HASH \
AttributeName=OrderId,KeyType=RANGE \
--global-secondary-indexes \
'[{"IndexName":"StatusIndex","KeySchema":[{"AttributeName":"Status","KeyType":"HASH"}],"Projection":{"ProjectionType":"ALL"},"BillingMode":"PAY_PER_REQUEST"}]' \
--billing-mode PAY_PER_REQUEST
3.3 查看表信息(describe-table, list-tables)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| describe-table | aws dynamodb describe-table --table-name name | 获取指定表的详细元数据(主键、索引、容量模式、状态等) | aws dynamodb describe-table --table-name Users | 返回 JSON 结构,包含 TableStatus(CREATING/ACTIVE/DELETING);可用于检查表是否就绪 |
| list-tables | aws dynamodb list-tables [--limit n] [--exclusive-start-table-name name] | 列出当前区域下所有 DynamoDB 表名 | aws dynamodb list-tables | 默认最多返回 100 个表名;分页需使用 --exclusive-start-table-name 参数 |
3.4 删除表(delete-table)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| delete-table | aws dynamodb delete-table --table-name name | 永久删除指定表及其所有数据 | aws dynamodb delete-table --table-name Users | 删除不可逆;表状态变为 DELETING,通常几秒内完成;删除期间无法重建同名表 |
3.5 修改表配置(update-table)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| update-table(修改容量模式) | aws dynamodb update-table \ --table-name name \ --billing-mode PAY_PER_REQUEST | 将表从预置模式切换为按需模式 | aws dynamodb update-table --table-name Orders --billing-mode PAY_PER_REQUEST | 切换有冷却期(通常 24 小时内只能切一次) |
| update-table(修改预置吞吐) | aws dynamodb update-table \ --table-name name \ --provisioned-throughput ReadCapacityUnits=r,WriteCapacityUnits=w | 调整预置读写容量单位 | aws dynamodb update-table --table-name Orders --provisioned-throughput ReadCapacityUnits=10,WriteCapacityUnits=5 | 仅适用于预置模式;每 24 小时最多 4 次下调,上调无限制 |
| update-table(添加 GSI) | aws dynamodb update-table \ --table-name name \ --global-secondary-index-updates '[{"Create":{...}}]' | 为现有表添加新的全局二级索引 | 见下方示例 | 添加 GSI 期间表仍可读写;新 GSI 状态为 CREATING,需等待变为 ACTIVE;不能修改或删除已有 GSI(只能新建) |
添加 GSI 示例:
aws dynamodb update-table \
--table-name Orders \
--global-secondary-index-updates \
'[{"Create":{"IndexName":"DateIndex","KeySchema":[{"AttributeName":"OrderDate","KeyType":"HASH"}],"Projection":{"ProjectionType":"KEYS_ONLY"},"BillingMode":"PAY_PER_REQUEST"}}]'
注意: DynamoDB 不支持直接修改主键结构。如需变更主键,必须创建新表并迁移数据。
第四章:数据读写操作(AWS CLI)
4.1 写入单个项(put-item)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| put-item | aws dynamodb put-item \ --table-name name \ --item json \ [--condition-expression expr] \ [--expression-attribute-names json] \ [--expression-attribute-values json] | 向表中插入或替换一个完整项 | 见下方示例 | 若主键已存在,则整项被覆盖;属性值必须使用 DynamoDB 类型封装(如 {"S":"..."});--item 可用 file://path/to/item.json 从文件读取 |
| 带条件写入 | 同上,增加 --condition-expression | 仅当条件为真时才写入(避免覆盖) | 见下方示例 | 条件表达式失败时返回 ConditionalCheckFailedException;常用于实现”仅创建”语义 |
put-item 示例:
aws dynamodb put-item \
--table-name Users \
--item '{
"UserId": {"S": "user123"},
"Name": {"S": "Alice"},
"Age": {"N": "30"}
}'
带条件写入示例:
aws dynamodb put-item \
--table-name Users \
--item '{
"UserId": {"S": "user123"},
"Status": {"S": "active"}
}' \
--condition-expression "attribute_not_exists(UserId)"
4.2 获取单个项(get-item)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| get-item | aws dynamodb get-item \ --table-name name \ --key json \ [--consistent-read | --no-consistent-read] \ [--projection-expression expr] \ [--expression-attribute-names json] | 根据主键获取单个项 | 见下方示例 | 必须提供完整的主键(含排序键,如有);默认为最终一致读;若项不存在,返回空 Item 字段 |
| 强一致读 | 同上,加 --consistent-read | 获取最新写入的数据 | 见下方示例 | 仅支持主表读取,不适用于 GSI;延迟略高,吞吐成本翻倍(1 RCU = 4KB) |
get-item 示例:
aws dynamodb get-item \
--table-name Users \
--key '{
"UserId": {"S": "user123"}
}'
强一致读示例:
aws dynamodb get-item \
--table-name Orders \
--key '{
"CustomerId": {"S": "cust1"},
"OrderId": {"S": "ord1001"}
}' \
--consistent-read
4.3 更新项(update-item)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| update-item | aws dynamodb update-item \ --table-name name \ --key json \ --update-expression expr \ [--condition-expression expr] \ [--expression-attribute-names json] \ [--expression-attribute-values json] \ [--return-values type] | 原子性地修改项的部分属性 | 见下方示例 | 支持 SET(赋值)、ADD(数值/集合加)、REMOVE(删除属性)、DELETE(集合删除元素);不会影响未提及的属性 |
| 原子计数器 | 使用 ADD 操作对 Number 类型累加 | 实现并发安全的计数 | 见下方示例 | ADD 对 Number 执行加法,对 Set 执行并集;即使多个客户端并发调用,结果也正确 |
| 条件更新 | 加 --condition-expression | 仅当条件满足时更新 | 见下方示例 | 防止超卖等业务逻辑错误;条件失败返回 ConditionalCheckFailedException |
update-item 示例:
aws dynamodb update-item \
--table-name Users \
--key '{
"UserId": {"S": "user123"}
}' \
--update-expression "SET LastLogin = :time" \
--expression-attribute-values '{
":time": {"S": "2025-04-05T10:00:00Z"}
}'
原子计数器示例:
aws dynamodb update-item \
--table-name Stats \
--key '{
"MetricId": {"S": "page_views"}
}' \
--update-expression "ADD Views :inc" \
--expression-attribute-values '{
":inc": {"N": "1"}
}'
条件更新示例:
aws dynamodb update-item \
--table-name Inventory \
--key '{
"ProductId": {"S": "prod1"}
}' \
--update-expression "SET Stock = Stock - :qty" \
--condition-expression "Stock >= :qty" \
--expression-attribute-values '{
":qty": {"N": "5"}
}'
4.4 删除项(delete-item)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| delete-item | aws dynamodb delete-item \ --table-name name \ --key json \ [--condition-expression expr] \ [--expression-attribute-names json] \ [--expression-attribute-values json] | 根据主键删除一项 | 见下方示例 | 删除操作幂等(重复删除无副作用);消耗 1 WCU(无论项大小) |
| 条件删除 | 同上,加 --condition-expression | 仅当条件成立时删除 | 见下方示例 | 常用于清理过期会话;条件失败时不删除,也不报错(静默失败) |
delete-item 示例:
aws dynamodb delete-item \
--table-name Users \
--key '{
"UserId": {"S": "user123"}
}'
条件删除示例:
aws dynamodb delete-item \
--table-name Sessions \
--key '{
"SessionId": {"S": "sess999"}
}' \
--condition-expression "ExpiresAt < :now" \
--expression-attribute-values '{
":now": {"N": "1712345678"}
}'
4.5 批量写入与读取(batch-write-item, batch-get-item)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| batch-write-item | aws dynamodb batch-write-item \ --request-items json \ [--return-consumed-capacity type] \ [--return-item-collection-metrics type] | 一次请求中执行最多 25 个 Put 或 Delete 操作 | 见下方示例 | 单次请求总大小 ≤ 16 MB;每个 Put/Delete 算独立操作;部分失败时返回 UnprocessedItems,需重试 |
| batch-get-item | aws dynamodb batch-get-item \ --request-items json \ [--return-consumed-capacity type] | 一次请求从一个或多个表读取最多 100 个项 | 见下方示例 | 最多跨 100 个不同分区键;响应可能分页(含 UnprocessedKeys);不支持强一致读(始终最终一致) |
| 多表批量读 | 在 request-items 中包含多个表 | 同时查询多个表 | 见下方示例 | 每个表的 Keys 独立指定;各表必须在同一区域 |
batch-write-item 示例:
aws dynamodb batch-write-item \
--request-items '{
"Users": [
{"PutRequest": {"Item": {"UserId": {"S": "u1"}, "Name": {"S": "Bob"}}}},
{"DeleteRequest": {"Key": {"UserId": {"S": "u2"}}}}
]
}'
batch-get-item 示例:
aws dynamodb batch-get-item \
--request-items '{
"Users": {
"Keys": [
{"UserId": {"S": "u1"}},
{"UserId": {"S": "u2"}}
],
"ProjectionExpression": "UserId, Name"
}
}'
多表批量读示例:
aws dynamodb batch-get-item \
--request-items '{
"Users": {"Keys": [{"UserId": {"S": "u1"}}]},
"Orders": {"Keys": [{"OrderId": {"S": "o1"}}]}
}'
注意: Batch 操作不保证原子性(部分成功部分失败是正常行为),应用层需处理
UnprocessedItems并重试。
第五章:查询与扫描(AWS CLI)
5.1 使用主键查询(query)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| query | aws dynamodb query \ --table-name name \ --key-condition-expression expr \ [--filter-expression expr] \ [--expression-attribute-names json] \ [--expression-attribute-values json] \ [--scan-index-forward | --no-scan-index-forward] \ [--limit n] \ [--consistent-read | --no-consistent-read] | 根据主键(分区键 + 可选排序键条件)高效查询项 | 见下方示例 | 必须指定完整的分区键;排序键支持 =, <, <=, >, >=, BETWEEN, BEGINS_WITH;默认按排序键升序返回 |
| 带排序范围查询 | 同上,使用排序键范围条件 | 查询某用户在特定时间范围内的订单 | 见下方示例 | 排序键必须为 String/Number/Binary;BETWEEN 包含边界值 |
| 降序查询 | 加 --no-scan-index-forward | 获取最新记录(如最近登录) | 见下方示例 | --no-scan-index-forward 表示降序;配合 --limit 1 可高效获取最新项 |
query 示例:
aws dynamodb query \
--table-name Orders \
--key-condition-expression "CustomerId = :cid" \
--expression-attribute-values '{
":cid": {"S": "cust123"}
}'
带排序范围查询示例:
aws dynamodb query \
--table-name Orders \
--key-condition-expression "CustomerId = :cid AND OrderDate BETWEEN :start AND :end" \
--expression-attribute-values '{
":cid": {"S": "cust123"},
":start": {"S": "2025-04-01"},
":end": {"S": "2025-04-05"}
}'
降序查询示例:
aws dynamodb query \
--table-name UserEvents \
--key-condition-expression "UserId = :uid" \
--expression-attribute-values '{
":uid": {"S": "user1"}
}' \
--no-scan-index-forward \
--limit 1
5.2 使用 GSI/LSI 查询(query with index)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| query with GSI | aws dynamodb query \ --table-name name \ --index-name gsi-name \ --key-condition-expression expr \ [...] | 通过全局二级索引查询数据 | 见下方示例 | 必须指定 --index-name;GSI 为最终一致,不支持 --consistent-read;投影属性缺失时无法返回非投影字段 |
| query with LSI | aws dynamodb query \ --table-name name \ --index-name lsi-name \ --key-condition-expression "PartitionKey = :pk AND SortKeyLSI op ..." \ [...] | 通过本地二级索引按不同排序键查询 | 见下方示例 | LSI 与主表共享分区键;支持强一致读(可加 --consistent-read);LSI 必须在建表时定义 |
| 复合 GSI 查询 | GSI 含排序键时使用范围条件 | 按状态和时间范围筛选 | 见下方示例 | GSI 的排序键也需高基数;避免对 GSI 执行全量扫描(性能差) |
query with GSI 示例:
aws dynamodb query \
--table-name Orders \
--index-name StatusIndex \
--key-condition-expression "Status = :status" \
--expression-attribute-values '{
":status": {"S": "pending"}
}'
query with LSI 示例:
aws dynamodb query \
--table-name Orders \
--index-name OrderByAmount \
--key-condition-expression "CustomerId = :cid" \
--expression-attribute-values '{
":cid": {"S": "cust123"}
}' \
--scan-index-forward false
复合 GSI 查询示例:
aws dynamodb query \
--table-name Orders \
--index-name StatusDateIndex \
--key-condition-expression "Status = :s AND CreatedAt >= :t" \
--expression-attribute-values '{
":s": {"S": "shipped"},
":t": {"S": "2025-04-01"}
}'
5.3 全表扫描(scan)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| scan | aws dynamodb scan \ --table-name name \ [--filter-expression expr] \ [--projection-expression expr] \ [--limit n] \ [--exclusive-start-key json] | 遍历整张表,返回匹配过滤条件的项 | 见下方示例 | 性能差、成本高(读取所有项再过滤);仅适用于小表或一次性任务;默认返回最多 1MB 数据 |
| 分段并行扫描 | 加 --total-segments 和 --segment | 将大表扫描拆分为多个并行任务 | 见下方示例 | 适用于大数据量导出;--segment 从 0 到 total-segments-1;各段独立执行,可并行 |
| 投影字段 | 使用 --projection-expression | 仅返回必要字段,减少网络和成本 | aws dynamodb scan \ --table-name Products \ --projection-expression "ProductId, Name" | 不减少 RCU 消耗(仍读整项),但减少传输量 |
scan 示例:
aws dynamodb scan \
--table-name Users \
--filter-expression "Age > :age" \
--expression-attribute-values '{
":age": {"N": "25"}
}'
分段并行扫描示例:
aws dynamodb scan \
--table-name Logs \
--total-segments 4 \
--segment 0 \
--filter-expression "Level = :err" \
--expression-attribute-values '{
":err": {"S": "ERROR"}
}'
5.4 分页与过滤表达式
| 功能 | 语法要素 | 说明 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 分页(Query/Scan) | 使用 --exclusive-start-key 参数传入上一页的 LastEvaluatedKey | DynamoDB 单次响应最多 1MB 数据,需分页获取全部结果 | 见下方示例 | LastEvaluatedKey 是不透明令牌,必须原样传递;不能跳页,必须顺序遍历 |
| 过滤表达式(FilterExpression) | --filter-expression + --expression-attribute-values | 在服务端对 Query/Scan 结果二次过滤 | 见下方示例 | Filter 不减少 RCU 消耗(先读再滤);仅用于减少返回数据量,不能替代 KeyCondition |
| 表达式属性名(避免保留字) | --expression-attribute-names | 当属性名是 DynamoDB 保留字(如 Status)时使用别名 | 见下方示例 | 常见保留字:Data, Timestamp, Status 等;必须用 # 开头定义别名 |
| 表达式属性值(安全参数化) | --expression-attribute-values | 避免直接拼接值,防止注入和类型错误 | 见上述所有示例 | 值必须带类型标签(如 {"S":"..."}, {"N":"123"});不可省略引号(即使数值也用字符串表示) |
分页查询示例:
# 第一次查询
aws dynamodb query \
--table-name Orders \
--key-condition-expression "CustomerId = :c" \
--expression-attribute-values '{":c":{"S":"cust1"}}' > page1.json
# 后续页(从 page1.json 提取 LastEvaluatedKey)
aws dynamodb query \
--table-name Orders \
--key-condition-expression "CustomerId = :c" \
--expression-attribute-values '{":c":{"S":"cust1"}}' \
--exclusive-start-key '{"CustomerId":{"S":"cust1"},"OrderId":{"S":"ord999"}}'
过滤表达式示例:
aws dynamodb query \
--table-name Orders \
--key-condition-expression "CustomerId = :c" \
--filter-expression "Total > :min" \
--expression-attribute-values '{
":c": {"S": "cust1"},
":min": {"N": "100"}
}'
表达式属性名示例:
aws dynamodb scan \
--table-name Items \
--filter-expression "#st = :val" \
--expression-attribute-names '{"#st":"Status"}' \
--expression-attribute-values '{":val":{"S":"active"}}'
第六章:高级功能与最佳实践
6.1 条件写入与原子操作(ConditionExpression)
| 功能/表达式 | 语法要素 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| attribute_not_exists | --condition-expression "attribute_not_exists(PK)" | 仅当项不存在时写入(防止覆盖) | 见下方示例 | 常用于注册、创建唯一资源;若主键已存在则抛出 ConditionalCheckFailedException |
| attribute_exists | --condition-expression "attribute_exists(PK)" | 仅当项存在时更新或删除 | 见下方示例 | 避免对不存在项操作;可用于幂等更新 |
| 字段值比较 | --condition-expression "Balance >= :amt" | 实现业务规则校验(如余额充足) | 见下方示例 | 支持 =, <>, <, <=, >, >=;数值比较按数学规则,字符串按字典序 |
| 多条件组合 | 使用 AND/OR/NOT | 复杂业务逻辑控制 | 见下方示例 | 括号控制优先级;避免过度复杂条件影响可读性 |
attribute_not_exists 示例:
aws dynamodb put-item \
--table-name Users \
--item '{"UserId":{"S":"u1"},"Name":{"S":"Alice"}}' \
--condition-expression "attribute_not_exists(UserId)"
attribute_exists 示例:
aws dynamodb update-item \
--table-name Sessions \
--key '{"SessionId":{"S":"s1"}}' \
--update-expression "SET Expired = :t" \
--condition-expression "attribute_exists(SessionId)" \
--expression-attribute-values '{":t":{"BOOL":true}}'
字段值比较示例:
aws dynamodb update-item \
--table-name Accounts \
--key '{"AccountId":{"S":"acc1"}}' \
--update-expression "SET Balance = Balance - :amt" \
--condition-expression "Balance >= :amt" \
--expression-attribute-values '{":amt":{"N":"50"}}'
多条件组合示例:
aws dynamodb delete-item \
--table-name Tasks \
--key '{"TaskId":{"S":"t1"}}' \
--condition-expression "(Status = :done) OR (Owner = :admin)" \
--expression-attribute-values '{
":done":{"S":"completed"},
":admin":{"S":"system"}
}'
6.2 乐观锁与版本控制
| 概念/操作 | 说明 | 实现方式 | 注意事项 |
|---|---|---|---|
| 版本字段 | 在项中增加 version(Number 类型)属性,每次更新递增 | 应用读取项 → 修改数据 → 更新时检查 version 未变 → 成功则 version+1 | 防止并发写入覆盖;适用于低频更新场景 |
| 条件更新实现乐观锁 | 使用 ConditionExpression 检查 version | 见下方示例 | 若 version 已被其他请求修改,条件失败;客户端需重试(读新 version → 重新应用变更) |
| 与 SDK 集成 | AWS SDK(如 DynamoDB Mapper)内置 @Versioned 注解 | 开发者无需手写 condition 表达式 | CLI 不直接支持,需手动构造;适合在应用层封装 |
条件更新实现乐观锁示例:
aws dynamodb update-item \
--table-name Documents \
--key '{"DocId":{"S":"doc1"}}' \
--update-expression "SET Content = :c, version = version + :inc" \
--condition-expression "version = :v" \
--expression-attribute-values '{
":c":{"S":"new content"},
":v":{"N":"3"},
":inc":{"N":"1"}
}'
6.3 TTL(Time To Live)自动过期
| 操作 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 启用 TTL | aws dynamodb update-time-to-live \ --table-name name \ --time-to-live-specification Enabled=true,AttributeName=attr | 指定一个 Number 类型属性作为过期时间戳(Unix 秒) | 见下方示例 | 属性值必须为未来 Unix 时间戳(秒);TTL 通常在过期后 48 小时内删除项 |
| 查看 TTL 状态 | aws dynamodb describe-time-to-live --table-name name | 检查是否启用及当前状态 | aws dynamodb describe-time-to-live --table-name Sessions | 返回状态:ENABLING, ENABLED, DISABLING, DISABLED |
| 设置过期项 | 写入时包含 TTL 属性 | 创建临时会话或缓存 | 见下方示例 | ExpiresAt = 当前时间 + 有效期(秒);过期项仍可被查询,直到后台清理 |
启用 TTL 示例:
aws dynamodb update-time-to-live \
--table-name Sessions \
--time-to-live-specification Enabled=true,AttributeName=ExpiresAt
设置过期项示例:
aws dynamodb put-item \
--table-name Cache \
--item '{
"Key": {"S": "temp1"},
"Value": {"S": "data"},
"ExpiresAt": {"N": "1712400000"}
}'
6.4 流(DynamoDB Streams)与事件驱动
| 概念/操作 | 说明 | 配置方式 | 注意事项 |
|---|---|---|---|
| DynamoDB Stream | 记录表中每项的修改事件(插入、更新、删除),保留最多 24 小时 | 创建表或 update-table 时设置 StreamSpecification | 支持三种视图:KEYS_ONLY(仅主键)、NEW_IMAGE(新项全量)、OLD_IMAGE(旧项全量)、NEW_AND_OLD_IMAGES(新旧对比) |
| 启用流 | 见下方示例 | 为现有表开启流 | 流 ARN 在 describe-table 输出中;开启后不可降级为无流 |
| 消费流事件 | 通过 Lambda、Kinesis Client Library (KCL) 或 EventBridge | AWS Lambda 可直接绑定流触发 | Lambda 自动批处理记录;需处理重复事件(至少一次交付);流不保证全局顺序,仅分区内有序 |
| CLI 查看流 | aws dynamodbstreams describe-stream --stream-arn arn | 获取流元数据和分片信息 | 分片(Shard)对应表的分区;分片会随表扩缩容而分裂/合并 |
启用流示例:
aws dynamodb update-table \
--table-name name \
--stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES
示例:Lambda 触发器可实现审计日志、同步到 Elasticsearch、发送通知等。
6.5 性能监控与指标(CloudWatch)
| 指标名称 | 说明 | 监控用途 | 注意事项 |
|---|---|---|---|
| ConsumedReadCapacityUnits / ConsumedWriteCapacityUnits | 实际消耗的 RCU/WCU | 判断是否接近预置容量上限 | 按需模式下仍可见,用于成本分析 |
| ThrottledRequests | 因超过容量限制被拒绝的请求次数 | 识别性能瓶颈或突发流量问题 | 高频 ThrottledRequests 需扩容或切换至按需模式 |
| SuccessfulRequestLatency | 请求成功时的延迟(毫秒) | 评估用户体验和系统响应能力 | P99 延迟 > 100ms 可能需优化主键设计 |
| SystemErrors / UserErrors | 系统错误或客户端错误(如权限不足) | 排查应用配置或权限问题 | UserErrors 常见于 IAM 策略缺失 |
| TimeToLiveDeletedItemCount | TTL 删除的项数量 | 验证自动清理是否生效 | 仅在启用 TTL 的表中出现 |
| 操作 | CLI 命令示例 | 说明 |
|---|---|---|
| 查看表指标 | 见下方示例 | 获取过去一小时的写入容量消耗(每5分钟聚合) |
查看表指标示例:
aws cloudwatch get-metric-statistics \
--namespace "AWS/DynamoDB" \
--metric-name "ConsumedWriteCapacityUnits" \
--dimensions Name=TableName,Value=Orders \
--start-time 2025-04-05T00:00:00Z \
--end-time 2025-04-05T01:00:00Z \
--period 300 \
--statistics Sum
建议: 结合 CloudWatch Alarms 设置阈值告警(如
ThrottledRequests > 0持续 5 分钟)。
第七章:安全与权限管理
7.1 IAM 策略与 DynamoDB 权限
| 概念/操作 | 说明 | 策略示例(JSON 片段) | 注意事项 |
|---|---|---|---|
| 最小权限原则 | 仅授予执行任务所需的最小 DynamoDB 操作权限 | 见下方示例 | 避免使用 "dynamodb:*";Resource 应精确到表或索引 ARN |
| 表级权限 | 控制对特定表的操作 | Resource: "arn:aws:dynamodb:region:account:table/TableName" | 支持通配符(如 table/User*),但需谨慎 |
| 索引级权限 | 单独授权 GSI/LSI 访问 | Resource: "arn:aws:dynamodb:region:account:table/TableName/index/IndexName" | 查询 GSI 需同时拥有主表和索引权限 |
| 条件键(Condition Keys) | 基于属性值限制访问(如仅允许访问自己的数据) | 见下方示例 | 仅适用于 Query/GetItem 的分区键;dynamodb:LeadingKeys 用于限制 PK 值 |
| 常用操作权限 | Read: GetItem, Query, Scan / Write: PutItem, UpdateItem, DeleteItem / Admin: CreateTable, DeleteTable, UpdateTable | 根据角色分配:应用服务——仅读写;运维人员——含 Admin | Batch 操作(如 batch-write-item)需对应单操作权限 |
最小权限原则策略示例:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:Query"
],
"Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/Users"
}
]
}
条件键策略示例:
{
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": ["${aws:username}"]
}
}
}
注意: IAM 策略不适用于 DynamoDB Local(本地开发环境),因其绕过 AWS 身份验证。
7.2 加密(静态加密与传输加密)
| 加密类型 | 说明 | 配置方式 | 注意事项 |
|---|---|---|---|
| 静态加密(Encryption at Rest) | 数据在磁盘上自动加密,默认使用 AWS 托管 KMS 密钥(aws/dynamodb) | 创建表时默认启用,无需额外操作 | 无法关闭;可自定义 KMS 密钥(CMK)以满足合规要求 |
| 自定义 KMS 密钥 | 使用客户托管密钥(Customer Managed Key) | 见下方示例 | 需预先在 KMS 中创建密钥并授权 DynamoDB 使用;切换密钥需 update-table |
| 传输加密(Encryption in Transit) | 客户端与 DynamoDB 之间的通信通过 TLS 加密 | 所有 AWS CLI / SDK 请求默认使用 HTTPS | 不可禁用;确保应用不强制使用 HTTP endpoint |
| 加密验证 | 通过 describe-table 查看 SSEDescription | aws dynamodb describe-table --table-name SecureData | grep -A5 SSE | 返回字段包括 Status(ENABLED)、SSEType、KMSMasterKeyArn |
自定义 KMS 密钥示例:
aws dynamodb create-table \
--table-name SecureData \
--attribute-definitions AttributeName=Id,AttributeType=S \
--key-schema AttributeName=Id,KeyType=HASH \
--sse-specification Enabled=true,SSEType=KMS,KMSMasterKeyId=alias/my-dynamo-key \
--billing-mode PAY_PER_REQUEST
合规提示: 静态加密满足 HIPAA、PCI DSS、GDPR 等法规要求;自定义 KMS 密钥支持密钥轮换和审计。
7.3 VPC 终端节点访问
| 概念/操作 | 说明 | 配置步骤 | 注意事项 |
|---|---|---|---|
| VPC 终端节点(VPC Endpoint) | 允许 VPC 内 EC2 实例私有访问 DynamoDB,无需经过公网或 NAT | 1. 在 VPC 控制台创建终端节点 2. 服务名称: com.amazonaws.region.dynamodb3. 选择子网和安全组 4. (可选)附加终端节点策略 | 流量不离开 AWS 网络;降低延迟和成本(免 NAT/公网费用) |
| 终端节点策略 | 控制哪些 IAM 用户/角色可通过此终端节点访问 DynamoDB | 见下方示例 | 可限制到特定表或操作;策略与 IAM 策略共同生效(交集) |
| CLI 访问行为 | 当 EC2 位于已配置终端节点的子网中,CLI 自动走私有网络 | 无需修改 CLI 命令;aws dynamodb list-tables 正常工作 | 若终端节点未覆盖所有可用区,部分请求可能失败;需确保安全组允许出站到终端节点 |
| 与公有访问共存 | 同一账户可同时存在 VPC 内私有访问和公网访问 | 公网访问仍受 IAM 和安全组控制 | 终端节点不影响非 VPC 资源(如本地开发机) |
终端节点策略示例:
{
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "dynamodb:*",
"Resource": "*"
}
]
}
限制: DynamoDB VPC 终端节点不支持跨区域访问;必须在目标区域创建终端节点。
第八章:本地开发与测试
8.1 使用 DynamoDB Local
| 步骤名称 | 操作细节 | 注意事项 |
|---|---|---|
| 下载 DynamoDB Local | 访问 AWS 官网下载压缩包:DynamoDB Local 下载页;或使用 Docker 镜像:amazon/dynamodb-local | 需 Java 8+ 运行环境(JRE);Docker 方式更便捷,无需手动管理 Java |
| 启动服务(Jar 方式) | 解压后执行:java -jar DynamoDBLocal.jar -sharedDb -port 8000 | -sharedDb:所有客户端共享同一数据库文件(默认为 shared-local-instance.db);默认端口 8000,可自定义 |
| 启动服务(Docker 方式) | docker run -p 8000:8000 amazon/dynamodb-local | 数据默认不持久化;加 -v $(pwd):/home/dynamodblocal/data 可挂载目录持久化 |
| 停止服务 | Ctrl+C(前台运行)或 docker stop <container-id> | 关闭后数据保留在 shared-local-instance.db(除非删除) |
| 重置数据 | 删除 shared-local-instance.db 文件并重启 | 适用于每次测试前清理状态 |
8.2 本地 CLI 操作示例
| 操作类型 | CLI 命令(需指定 --endpoint-url) | 说明 | 注意事项 |
|---|---|---|---|
| 创建表 | aws dynamodb create-table \ --table-name TestTable \ --attribute-definitions AttributeName=Id,AttributeType=S \ --key-schema AttributeName=Id,KeyType=HASH \ --billing-mode PAY_PER_REQUEST \ --endpoint-url http://localhost:8000 | 在本地实例创建表 | 必须添加 --endpoint-url http://localhost:8000;区域(region)可任意(如 us-east-1),但需配置 |
| 写入数据 | aws dynamodb put-item \ --table-name TestTable \ --item '{"Id":{"S":"item1"},"Data":{"S":"hello"}}' \ --endpoint-url http://localhost:8000 | 插入测试项 | 本地无 IAM 验证,无需真实凭证(但 CLI 仍需配置 dummy 凭证) |
| 查询数据 | aws dynamodb get-item \ --table-name TestTable \ --key '{"Id":{"S":"item1"}}' \ --endpoint-url http://localhost:8000 | 获取单个项 | 返回格式与云端一致 |
| 列出所有表 | aws dynamodb list-tables --endpoint-url http://localhost:8000 | 查看本地存在的表 | 用于验证表是否创建成功 |
| 删除表 | aws dynamodb delete-table \ --table-name TestTable \ --endpoint-url http://localhost:8000 | 清理测试表 | 表删除后不可恢复 |
凭证配置建议: 执行
aws configure时,Access Key 和 Secret 可填任意值(如fake/fake),因本地模式不校验。
8.3 与应用程序集成(如 Node.js / Python)
| 语言/SDK | 配置方式 | 最小可运行代码示例 | 注意事项 |
|---|---|---|---|
| Node.js (AWS SDK v3) | 安装依赖:npm install @aws-sdk/client-dynamodb,创建客户端时指定 endpoint | 见下方示例 | 必须显式设置 endpoint;credentials 可为任意值 |
| Python (boto3) | 安装:pip install boto3,创建 resource 或 client 时传 endpoint_url | 见下方示例 | boto3 默认读取 ~/.aws/credentials,但本地可覆盖;使用 resource 接口更简洁 |
| 通用集成原则 | 所有 AWS SDK 均支持自定义 endpoint | — | 适用于 Java、Go、.NET 等;单元测试中常配合 Jest / pytest 使用 |
| 与生产代码共用 | 通过环境变量切换 endpoint | if (process.env.IS_LOCAL) { config.endpoint = "http://localhost:8000"; } | 避免硬编码;确保生产环境不启用本地 endpoint |
Node.js (AWS SDK v3) 示例:
import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb";
const client = new DynamoDBClient({
region: "us-east-1",
endpoint: "http://localhost:8000",
credentials: {
accessKeyId: "fake",
secretAccessKey: "fake"
}
});
await client.send(new PutItemCommand({
TableName: "TestTable",
Item: {
Id: { S: "app1" },
Data: { S: "from node" }
}
}));
Python (boto3) 示例:
import boto3
dynamodb = boto3.resource(
'dynamodb',
endpoint_url='http://localhost:8000',
region_name='us-east-1',
aws_access_key_id='fake',
aws_secret_access_key='fake'
)
table = dynamodb.Table('TestTable')
table.put_item(Item={'Id': 'py1', 'Data': 'from python'})
提示: DynamoDB Local 不支持 TTL、Streams、Backup 等高级功能,仅用于基本 CRUD 和查询逻辑验证。