dynamodb

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

AWS DynamoDB

AWS DynamoDB

Amazon DynamoDB is a fully managed NoSQL database service providing fast, predictable performance at any scale. It supports key-value and document data structures.
Amazon DynamoDB 是一项全托管的NoSQL数据库服务,可在任何规模下提供快速、可预测的性能。它支持键值和文档数据结构。

Table of Contents

目录

Core Concepts

核心概念

Keys

键(Keys)

Key TypeDescription
Partition Key (PK)Required. Determines data distribution
Sort Key (SK)Optional. Enables range queries within partition
Composite KeyPK + SK combination
键类型描述
Partition Key (PK)必填项,决定数据分布
Sort Key (SK)可选项,支持在分区内执行范围查询
Composite KeyPK + SK 的组合

Secondary Indexes

二级索引

Index TypeDescription
GSI (Global Secondary Index)Different PK/SK, separate throughput, eventually consistent
LSI (Local Secondary Index)Same PK, different SK, shares table throughput, strongly consistent option
索引类型描述
GSI (Global Secondary Index)使用不同的PK/SK,拥有独立吞吐量,最终一致性
LSI (Local Secondary Index)使用相同的PK,不同的SK,共享表吞吐量,支持强一致性选项

Capacity Modes

容量模式

ModeUse Case
On-DemandUnpredictable traffic, pay-per-request
ProvisionedPredictable traffic, lower cost, can use auto-scaling
模式使用场景
On-Demand流量不可预测场景,按请求付费
Provisioned流量可预测场景,成本更低,可使用自动扩缩容

Common Patterns

常见模式

Create a Table

创建表

AWS CLI:
bash
aws dynamodb create-table \
  --table-name Users \
  --attribute-definitions \
    AttributeName=PK,AttributeType=S \
    AttributeName=SK,AttributeType=S \
  --key-schema \
    AttributeName=PK,KeyType=HASH \
    AttributeName=SK,KeyType=RANGE \
  --billing-mode PAY_PER_REQUEST
boto3:
python
import boto3

dynamodb = boto3.resource('dynamodb')

table = dynamodb.create_table(
    TableName='Users',
    KeySchema=[
        {'AttributeName': 'PK', 'KeyType': 'HASH'},
        {'AttributeName': 'SK', 'KeyType': 'RANGE'}
    ],
    AttributeDefinitions=[
        {'AttributeName': 'PK', 'AttributeType': 'S'},
        {'AttributeName': 'SK', 'AttributeType': 'S'}
    ],
    BillingMode='PAY_PER_REQUEST'
)

table.wait_until_exists()
AWS CLI:
bash
aws dynamodb create-table \
  --table-name Users \
  --attribute-definitions \
    AttributeName=PK,AttributeType=S \
    AttributeName=SK,AttributeType=S \
  --key-schema \
    AttributeName=PK,KeyType=HASH \
    AttributeName=SK,KeyType=RANGE \
  --billing-mode PAY_PER_REQUEST
boto3:
python
import boto3

dynamodb = boto3.resource('dynamodb')

table = dynamodb.create_table(
    TableName='Users',
    KeySchema=[
        {'AttributeName': 'PK', 'KeyType': 'HASH'},
        {'AttributeName': 'SK', 'KeyType': 'RANGE'}
    ],
    AttributeDefinitions=[
        {'AttributeName': 'PK', 'AttributeType': 'S'},
        {'AttributeName': 'SK', 'AttributeType': 'S'}
    ],
    BillingMode='PAY_PER_REQUEST'
)

table.wait_until_exists()

Basic CRUD Operations

基础CRUD操作

python
import boto3
from boto3.dynamodb.conditions import Key, Attr

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Users')
python
import boto3
from boto3.dynamodb.conditions import Key, Attr

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Users')

Put item

插入条目

table.put_item( Item={ 'PK': 'USER#123', 'SK': 'PROFILE', 'name': 'John Doe', 'email': 'john@example.com', 'created_at': '2024-01-15T10:30:00Z' } )
table.put_item( Item={ 'PK': 'USER#123', 'SK': 'PROFILE', 'name': 'John Doe', 'email': 'john@example.com', 'created_at': '2024-01-15T10:30:00Z' } )

Get item

获取条目

response = table.get_item( Key={'PK': 'USER#123', 'SK': 'PROFILE'} ) item = response.get('Item')
response = table.get_item( Key={'PK': 'USER#123', 'SK': 'PROFILE'} ) item = response.get('Item')

Update item

更新条目

table.update_item( Key={'PK': 'USER#123', 'SK': 'PROFILE'}, UpdateExpression='SET #name = :name, updated_at = :updated', ExpressionAttributeNames={'#name': 'name'}, ExpressionAttributeValues={ ':name': 'John Smith', ':updated': '2024-01-16T10:30:00Z' } )
table.update_item( Key={'PK': 'USER#123', 'SK': 'PROFILE'}, UpdateExpression='SET #name = :name, updated_at = :updated', ExpressionAttributeNames={'#name': 'name'}, ExpressionAttributeValues={ ':name': 'John Smith', ':updated': '2024-01-16T10:30:00Z' } )

Delete item

删除条目

table.delete_item( Key={'PK': 'USER#123', 'SK': 'PROFILE'} )
undefined
table.delete_item( Key={'PK': 'USER#123', 'SK': 'PROFILE'} )
undefined

Query Operations

查询操作

python
undefined
python
undefined

Query by partition key

按分区键查询

response = table.query( KeyConditionExpression=Key('PK').eq('USER#123') )
response = table.query( KeyConditionExpression=Key('PK').eq('USER#123') )

Query with sort key condition

带排序键条件的查询

response = table.query( KeyConditionExpression=Key('PK').eq('USER#123') & Key('SK').begins_with('ORDER#') )
response = table.query( KeyConditionExpression=Key('PK').eq('USER#123') & Key('SK').begins_with('ORDER#') )

Query with filter

带过滤条件的查询

response = table.query( KeyConditionExpression=Key('PK').eq('USER#123'), FilterExpression=Attr('status').eq('active') )
response = table.query( KeyConditionExpression=Key('PK').eq('USER#123'), FilterExpression=Attr('status').eq('active') )

Query with projection

带投影的查询

response = table.query( KeyConditionExpression=Key('PK').eq('USER#123'), ProjectionExpression='PK, SK, #name, email', ExpressionAttributeNames={'#name': 'name'} )
response = table.query( KeyConditionExpression=Key('PK').eq('USER#123'), ProjectionExpression='PK, SK, #name, email', ExpressionAttributeNames={'#name': 'name'} )

Paginated query

分页查询

paginator = dynamodb.meta.client.get_paginator('query') for page in paginator.paginate( TableName='Users', KeyConditionExpression='PK = :pk', ExpressionAttributeValues={':pk': {'S': 'USER#123'}} ): for item in page['Items']: print(item)
undefined
paginator = dynamodb.meta.client.get_paginator('query') for page in paginator.paginate( TableName='Users', KeyConditionExpression='PK = :pk', ExpressionAttributeValues={':pk': {'S': 'USER#123'}} ): for item in page['Items']: print(item)
undefined

Batch Operations

批量操作

python
undefined
python
undefined

Batch write (up to 25 items)

批量写入(最多25条条目)

with table.batch_writer() as batch: for i in range(100): batch.put_item(Item={ 'PK': f'USER#{i}', 'SK': 'PROFILE', 'name': f'User {i}' })
with table.batch_writer() as batch: for i in range(100): batch.put_item(Item={ 'PK': f'USER#{i}', 'SK': 'PROFILE', 'name': f'User {i}' })

Batch get (up to 100 items)

批量获取(最多100条条目)

dynamodb = boto3.resource('dynamodb') response = dynamodb.batch_get_item( RequestItems={ 'Users': { 'Keys': [ {'PK': 'USER#1', 'SK': 'PROFILE'}, {'PK': 'USER#2', 'SK': 'PROFILE'} ] } } )
undefined
dynamodb = boto3.resource('dynamodb') response = dynamodb.batch_get_item( RequestItems={ 'Users': { 'Keys': [ {'PK': 'USER#1', 'SK': 'PROFILE'}, {'PK': 'USER#2', 'SK': 'PROFILE'} ] } } )
undefined

Create GSI

创建GSI

bash
aws dynamodb update-table \
  --table-name Users \
  --attribute-definitions AttributeName=email,AttributeType=S \
  --global-secondary-index-updates '[
    {
      "Create": {
        "IndexName": "email-index",
        "KeySchema": [{"AttributeName": "email", "KeyType": "HASH"}],
        "Projection": {"ProjectionType": "ALL"}
      }
    }
  ]'
bash
aws dynamodb update-table \
  --table-name Users \
  --attribute-definitions AttributeName=email,AttributeType=S \
  --global-secondary-index-updates '[
    {
      "Create": {
        "IndexName": "email-index",
        "KeySchema": [{"AttributeName": "email", "KeyType": "HASH"}],
        "Projection": {"ProjectionType": "ALL"}
      }
    }
  ]'

Conditional Writes

条件写入

python
from botocore.exceptions import ClientError
python
from botocore.exceptions import ClientError

Only put if item doesn't exist

仅当条目不存在时插入

try: table.put_item( Item={'PK': 'USER#123', 'SK': 'PROFILE', 'name': 'John'}, ConditionExpression='attribute_not_exists(PK)' ) except ClientError as e: if e.response['Error']['Code'] == 'ConditionalCheckFailedException': print("Item already exists")
try: table.put_item( Item={'PK': 'USER#123', 'SK': 'PROFILE', 'name': 'John'}, ConditionExpression='attribute_not_exists(PK)' ) except ClientError as e: if e.response['Error']['Code'] == 'ConditionalCheckFailedException': print("条目已存在")

Optimistic locking with version

基于版本的乐观锁更新

table.update_item( Key={'PK': 'USER#123', 'SK': 'PROFILE'}, UpdateExpression='SET #name = :name, version = version + :inc', ConditionExpression='version = :current_version', ExpressionAttributeNames={'#name': 'name'}, ExpressionAttributeValues={ ':name': 'New Name', ':inc': 1, ':current_version': 5 } )
undefined
table.update_item( Key={'PK': 'USER#123', 'SK': 'PROFILE'}, UpdateExpression='SET #name = :name, version = version + :inc', ConditionExpression='version = :current_version', ExpressionAttributeNames={'#name': 'name'}, ExpressionAttributeValues={ ':name': 'New Name', ':inc': 1, ':current_version': 5 } )
undefined

CLI Reference

CLI参考

Table Operations

表操作

CommandDescription
aws dynamodb create-table
Create table
aws dynamodb describe-table
Get table info
aws dynamodb update-table
Modify table/indexes
aws dynamodb delete-table
Delete table
aws dynamodb list-tables
List all tables
命令描述
aws dynamodb create-table
创建表
aws dynamodb describe-table
获取表信息
aws dynamodb update-table
修改表/索引
aws dynamodb delete-table
删除表
aws dynamodb list-tables
列出所有表

Item Operations

条目操作

CommandDescription
aws dynamodb put-item
Create/replace item
aws dynamodb get-item
Read single item
aws dynamodb update-item
Update item attributes
aws dynamodb delete-item
Delete item
aws dynamodb query
Query by key
aws dynamodb scan
Full table scan
命令描述
aws dynamodb put-item
创建/替换条目
aws dynamodb get-item
读取单个条目
aws dynamodb update-item
更新条目属性
aws dynamodb delete-item
删除条目
aws dynamodb query
按键查询
aws dynamodb scan
全表扫描

Batch Operations

批量操作

CommandDescription
aws dynamodb batch-write-item
Batch write (25 max)
aws dynamodb batch-get-item
Batch read (100 max)
aws dynamodb transact-write-items
Transaction write
aws dynamodb transact-get-items
Transaction read
命令描述
aws dynamodb batch-write-item
批量写入(最多25条)
aws dynamodb batch-get-item
批量读取(最多100条)
aws dynamodb transact-write-items
事务写入
aws dynamodb transact-get-items
事务读取

Best Practices

最佳实践

Data Modeling

数据建模

  • Design for access patterns — know your queries before designing
  • Use composite keys — PK for grouping, SK for sorting/filtering
  • Prefer query over scan — scans are expensive
  • Use sparse indexes — only items with index attributes are indexed
  • Consider single-table design for related entities
  • 围绕访问模式设计 — 在设计前明确查询需求
  • 使用复合键 — PK用于分组,SK用于排序/过滤
  • 优先使用查询而非扫描 — 扫描成本高昂
  • 使用稀疏索引 — 仅对包含索引属性的条目建立索引
  • 考虑单表设计来管理关联实体

Performance

性能优化

  • Distribute partition keys evenly — avoid hot partitions
  • Use batch operations to reduce API calls
  • Enable DAX for read-heavy workloads
  • Use projections to reduce data transfer
  • 均匀分布分区键 — 避免热点分区
  • 使用批量操作减少API调用次数
  • 启用DAX应对读密集型工作负载
  • 使用投影减少数据传输量

Cost Optimization

成本优化

  • Use on-demand for variable workloads
  • Use provisioned + auto-scaling for predictable workloads
  • Set TTL for expiring data
  • Archive to S3 for cold data
  • 按需模式适用于可变工作负载
  • 预留容量+自动扩缩容适用于可预测工作负载
  • 设置TTL自动过期数据
  • 归档到S3存储冷数据

Troubleshooting

故障排查

Throttling

限流问题

Symptom:
ProvisionedThroughputExceededException
Causes:
  • Hot partition (uneven key distribution)
  • Burst traffic exceeding capacity
  • GSI throttling affecting base table
Solutions:
python
undefined
症状:
ProvisionedThroughputExceededException
原因:
  • 热点分区(键分布不均)
  • 突发流量超出容量
  • GSI限流影响主表
解决方案:
python
undefined

Use exponential backoff

使用指数退避

import time from botocore.config import Config
config = Config( retries={ 'max_attempts': 10, 'mode': 'adaptive' } ) dynamodb = boto3.resource('dynamodb', config=config)
undefined
import time from botocore.config import Config
config = Config( retries={ 'max_attempts': 10, 'mode': 'adaptive' } ) dynamodb = boto3.resource('dynamodb', config=config)
undefined

Hot Partitions

热点分区

Debug:
bash
undefined
调试:
bash
undefined

Check consumed capacity by partition

按分区查看已消耗容量

aws cloudwatch get-metric-statistics
--namespace AWS/DynamoDB
--metric-name ConsumedReadCapacityUnits
--dimensions Name=TableName,Value=Users
--start-time $(date -d '1 hour ago' -u +%Y-%m-%dT%H:%M:%SZ)
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ)
--period 60
--statistics Sum

**Solutions:**
- Add randomness to partition keys
- Use write sharding
- Distribute access across partitions
aws cloudwatch get-metric-statistics
--namespace AWS/DynamoDB
--metric-name ConsumedReadCapacityUnits
--dimensions Name=TableName,Value=Users
--start-time $(date -d '1 hour ago' -u +%Y-%m-%dT%H:%M:%SZ)
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ)
--period 60
--statistics Sum

**解决方案:**
- 为分区键添加随机性
- 使用写入分片
- 跨分区分散访问

Query Returns No Items

查询无返回结果

Debug checklist:
  1. Verify key values exactly match (case-sensitive)
  2. Check key types (S, N, B)
  3. Confirm table/index name
  4. Review filter expressions (they apply AFTER read)
调试清单:
  1. 验证键值完全匹配(区分大小写)
  2. 检查键类型(S、N、B)
  3. 确认表/索引名称正确
  4. 检查过滤表达式(过滤在读取后执行)

Scan Performance

扫描性能问题

Issue: Scans are slow and expensive
Solutions:
  • Use parallel scan for large tables
  • Create GSI for the access pattern
  • Use filter expressions to reduce returned data
python
undefined
问题: 扫描速度慢且成本高
解决方案:
  • 对大型表使用并行扫描
  • 为该访问模式创建GSI
  • 使用过滤表达式减少返回数据量
python
undefined

Parallel scan

并行扫描

import concurrent.futures
def scan_segment(segment, total_segments): return table.scan( Segment=segment, TotalSegments=total_segments )
with concurrent.futures.ThreadPoolExecutor() as executor: results = list(executor.map( lambda s: scan_segment(s, 4), range(4) ))
undefined
import concurrent.futures
def scan_segment(segment, total_segments): return table.scan( Segment=segment, TotalSegments=total_segments )
with concurrent.futures.ThreadPoolExecutor() as executor: results = list(executor.map( lambda s: scan_segment(s, 4), range(4) ))
undefined

References

参考资料