mcpField
D
dynamodb

dynamodb

github.com/itsmostafa数据与数据库1.2k145 次安装2 天前更新
代码仓库

关于 dynamodb

面向 Amazon DynamoDB 开发者的实用参考技能,涵盖数据建模、AWS CLI 与 boto3 操作,以及性能、成本和故障排查。

主要功能

  1. 01键与索引设计
  2. 02表和项目操作
  3. 03查询与批处理模式
  4. 04容量与成本指导
  5. 05排查限流问题

适用场景

  1. 01规划分区键和排序键
  2. 02使用 CLI 创建或更新表
  3. 03诊断查询缓慢或限流

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/itsmostafa/aws-agent-skills --skill dynamodb

安装后在 Claude Code 中输入/dynamodb确认已加载。

附带文件query-patterns.md

详细介绍

AWS DynamoDB

Amazon DynamoDB 是一项完全托管的 NoSQL 数据库服务,可在任何规模下提供快速、可预测的性能。它支持键值和文档数据结构。

目录

核心概念

键
键类型描述
分区键(PK)必需。决定数据分布
排序键(SK)可选。支持在分区内进行范围查询
复合键PK + SK 组合
二级索引
索引类型描述
GSI(全局二级索引)PK/SK 不同,吞吐量独立,最终一致
LSI(本地二级索引)PK 相同、SK 不同,与表共享吞吐量,可选择强一致性
容量模式
模式适用场景
按需流量不可预测,按请求付费
预置流量可预测,成本较低,可使用自动扩缩容

常见模式

创建表

AWS CLI:

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:

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()
基本 CRUD 操作
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': '[email protected]',
        'created_at': '2024-01-15T10:30:00Z'
    }
)

# 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'
    }
)

# Delete item
table.delete_item(
    Key={'PK': 'USER#123', 'SK': 'PROFILE'}
)
查询操作
# Query by partition key
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#')
)

# Query with filter
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'}
)

# 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)
批量操作
# Batch write (up to 25 items)
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)
dynamodb = boto3.resource('dynamodb')
response = dynamodb.batch_get_item(
    RequestItems={
        'Users': {
            'Keys': [
                {'PK': 'USER#1', 'SK': 'PROFILE'},
                {'PK': 'USER#2', 'SK': 'PROFILE'}
            ]
        }
    }
)
创建 GSI
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"}
      }
    }
  ]'
条件写入
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")

# 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
    }
)

CLI 参考

表操作
命令描述
aws dynamodb create-table创建表
aws dynamodb describe-table获取表信息
aws dynamodb update-table修改表/索引
aws dynamodb delete-table删除表
aws dynamodb list-tables列出所有表
项目操作
命令描述
aws dynamodb put-item创建/替换项目
aws dynamodb get-item读取单个项目
aws dynamodb update-item更新项目属性
aws dynamodb delete-item删除项目
aws dynamodb query按键查询
aws dynamodb scan扫描整个表
批量操作
命令描述
aws dynamodb batch-write-item批量写入(最多 25 个)
aws dynamodb batch-get-item批量读取(最多 100 个)
aws dynamodb transact-write-items事务写入
aws dynamodb transact-get-items事务读取

最佳实践

数据建模
  • 围绕访问模式设计 — 设计前先了解查询需求
  • 使用复合键 — PK 用于分组,SK 用于排序/筛选
  • 优先使用 query,而非 scan — scan 开销较大
  • 使用稀疏索引 — 只有包含索引属性的项目才会被索引
  • 对相关实体考虑采用单表设计
性能
  • 均匀分布分区键 — 避免热点分区
  • 使用批量操作以减少 API 调用
  • 为读密集型工作负载启用 DAX
  • 使用投影以减少数据传输
成本优化
  • 可变工作负载使用按需模式
  • 可预测的工作负载使用预置容量 + 自动扩缩容
  • 为过期数据设置 TTL
  • 将冷数据归档到 S3

故障排查

限流

症状: ProvisionedThroughputExceededException

原因:

  • 热点分区(键分布不均)
  • 突发流量超出容量
  • GSI 限流影响基表

解决方案:

# Use exponential backoff
import time
from botocore.config import Config

config = Config(
    retries={
        'max_attempts': 10,
        'mode': 'adaptive'
    }
)
dynamodb = boto3.resource('dynamodb', config=config)
热点分区

调试:

# 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

解决方案:

  • 为分区键添加随机性
  • 使用写分片
  • 将访问分散到多个分区
查询未返回任何项目

调试检查清单:

  1. 确认键值完全匹配(区分大小写)
  2. 检查键类型(S、N、B)
  3. 确认表/索引名称
  4. 检查筛选表达式(它们会在读取之后应用)
扫描性能

问题: 扫描速度慢且成本高

解决方案:

  • 对大型表使用并行扫描
  • 为访问模式创建 GSI
  • 使用筛选表达式减少返回的数据
# 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)
    ))

参考资料

评论

支持 Markdown