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. 02CLIでのテーブル作成や更新
  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 は並べ替え/フィルタリングに使用します
  • スキャンよりクエリを優先する — スキャンはコストがかかります
  • スパースインデックスを使用する — インデックス属性を持つアイテムのみがインデックス化されます
  • 関連するエンティティにはシングルテーブル設計を検討します
パフォーマンス
  • パーティションキーを均等に分散する — ホットパーティションを避けます
  • バッチ操作を使用する — 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)
    ))

参考資料

コメント