dynamodb
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAWS 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 Type | Description |
|---|---|
| Partition Key (PK) | Required. Determines data distribution |
| Sort Key (SK) | Optional. Enables range queries within partition |
| Composite Key | PK + SK combination |
| 键类型 | 描述 |
|---|---|
| Partition Key (PK) | 必填项,决定数据分布 |
| Sort Key (SK) | 可选项,支持在分区内执行范围查询 |
| Composite Key | PK + SK 的组合 |
Secondary Indexes
二级索引
| Index Type | Description |
|---|---|
| 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
容量模式
| Mode | Use Case |
|---|---|
| On-Demand | Unpredictable traffic, pay-per-request |
| Provisioned | Predictable 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_REQUESTboto3:
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_REQUESTboto3:
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'}
)
undefinedtable.delete_item(
Key={'PK': 'USER#123', 'SK': 'PROFILE'}
)
undefinedQuery Operations
查询操作
python
undefinedpython
undefinedQuery 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)
undefinedpaginator = 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)
undefinedBatch Operations
批量操作
python
undefinedpython
undefinedBatch 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'}
]
}
}
)
undefineddynamodb = boto3.resource('dynamodb')
response = dynamodb.batch_get_item(
RequestItems={
'Users': {
'Keys': [
{'PK': 'USER#1', 'SK': 'PROFILE'},
{'PK': 'USER#2', 'SK': 'PROFILE'}
]
}
}
)
undefinedCreate 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 ClientErrorpython
from botocore.exceptions import ClientErrorOnly 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
}
)
undefinedtable.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
}
)
undefinedCLI Reference
CLI参考
Table Operations
表操作
| Command | Description |
|---|---|
| Create table |
| Get table info |
| Modify table/indexes |
| Delete table |
| List all tables |
| 命令 | 描述 |
|---|---|
| 创建表 |
| 获取表信息 |
| 修改表/索引 |
| 删除表 |
| 列出所有表 |
Item Operations
条目操作
| Command | Description |
|---|---|
| Create/replace item |
| Read single item |
| Update item attributes |
| Delete item |
| Query by key |
| Full table scan |
| 命令 | 描述 |
|---|---|
| 创建/替换条目 |
| 读取单个条目 |
| 更新条目属性 |
| 删除条目 |
| 按键查询 |
| 全表扫描 |
Batch Operations
批量操作
| Command | Description |
|---|---|
| Batch write (25 max) |
| Batch read (100 max) |
| Transaction write |
| Transaction read |
| 命令 | 描述 |
|---|---|
| 批量写入(最多25条) |
| 批量读取(最多100条) |
| 事务写入 |
| 事务读取 |
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:
ProvisionedThroughputExceededExceptionCauses:
- Hot partition (uneven key distribution)
- Burst traffic exceeding capacity
- GSI throttling affecting base table
Solutions:
python
undefined症状:
ProvisionedThroughputExceededException原因:
- 热点分区(键分布不均)
- 突发流量超出容量
- GSI限流影响主表
解决方案:
python
undefinedUse exponential backoff
使用指数退避
import time
from botocore.config import Config
config = Config(
retries={
'max_attempts': 10,
'mode': 'adaptive'
}
)
dynamodb = boto3.resource('dynamodb', config=config)
undefinedimport time
from botocore.config import Config
config = Config(
retries={
'max_attempts': 10,
'mode': 'adaptive'
}
)
dynamodb = boto3.resource('dynamodb', config=config)
undefinedHot Partitions
热点分区
Debug:
bash
undefined调试:
bash
undefinedCheck 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
--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 partitionsaws 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
--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:
- Verify key values exactly match (case-sensitive)
- Check key types (S, N, B)
- Confirm table/index name
- Review filter expressions (they apply AFTER read)
调试清单:
- 验证键值完全匹配(区分大小写)
- 检查键类型(S、N、B)
- 确认表/索引名称正确
- 检查过滤表达式(过滤在读取后执行)
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
undefinedParallel 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)
))
undefinedimport 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