Article

键值型数据库DynamoDB

更新于:2026-07-16

第一章:DynamoDB 基础概念

1.1 什么是 DynamoDB

概念名称说明注意事项
DynamoDBAmazon 提供的完全托管、高可用、低延迟的 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 使用排序键实现多维查询

功能说明操作支持注意事项
范围查询在相同分区键下,按排序键进行 ><BETWEENBEGINS_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_ONLYINCLUDE(指定属性)、ALLALL 投影会增加存储成本和写入延迟。
一致性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 策略、监控、备份管理复杂化。

单表示例结构:

PKSKTypeNameTotal
USER#alicePROFILEUserAlice
USER#aliceORDER#1001Order99.99
ORDER#1001ITEM#AItemLaptop

第三章: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-tableaws 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-tableaws dynamodb describe-table --table-name name获取指定表的详细元数据(主键、索引、容量模式、状态等)aws dynamodb describe-table --table-name Users返回 JSON 结构,包含 TableStatusCREATING/ACTIVE/DELETING);可用于检查表是否就绪
list-tablesaws 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-tableaws 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-itemaws 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-itemaws 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-itemaws 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-itemaws 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-itemaws 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-itemaws 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)

方法名称语法用途代码示例注意事项
queryaws 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 GSIaws dynamodb query \ --table-name name \ --index-name gsi-name \ --key-condition-expression expr \ [...]通过全局二级索引查询数据见下方示例必须指定 --index-name;GSI 为最终一致,不支持 --consistent-read;投影属性缺失时无法返回非投影字段
query with LSIaws 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)

方法名称语法用途代码示例注意事项
scanaws dynamodb scan \ --table-name name \ [--filter-expression expr] \ [--projection-expression expr] \ [--limit n] \ [--exclusive-start-key json]遍历整张表,返回匹配过滤条件的项见下方示例性能差、成本高(读取所有项再过滤);仅适用于小表或一次性任务;默认返回最多 1MB 数据
分段并行扫描--total-segments--segment将大表扫描拆分为多个并行任务见下方示例适用于大数据量导出;--segment0total-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 参数传入上一页的 LastEvaluatedKeyDynamoDB 单次响应最多 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)自动过期

操作语法用途代码示例注意事项
启用 TTLaws 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) 或 EventBridgeAWS 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 策略缺失
TimeToLiveDeletedItemCountTTL 删除的项数量验证自动清理是否生效仅在启用 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根据角色分配:应用服务——仅读写;运维人员——含 AdminBatch 操作(如 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 查看 SSEDescriptionaws dynamodb describe-table --table-name SecureData | grep -A5 SSE返回字段包括 StatusENABLED)、SSETypeKMSMasterKeyArn

自定义 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,无需经过公网或 NAT1. 在 VPC 控制台创建终端节点
2. 服务名称:com.amazonaws.region.dynamodb
3. 选择子网和安全组
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 使用
与生产代码共用通过环境变量切换 endpointif (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 和查询逻辑验证。