

# インデックスを管理するときのリレーショナル (SQL) データベースと DynamoDB の相違点
<a name="SQLtoNoSQL.Indexes"></a>

インデックスは代替のクエリパターンへのアクセスを付与し、クエリを高速化できます。このセクションでは、SQL と Amazon DynamoDB におけるインデックスの作成と使用を比較します。

リレーショナルデータベースまたは DynamoDB のいずれを使用するにしても、インデックスの作成は慎重に判断する必要があります。テーブルに書き込みが発生するたびに、テーブルのインデックスはすべて、更新する必要があります。大きなテーブルでの書き込み量が多い環境では、大量のシステムリソースを消費する可能性があります。読み取り専用または読み取りがほとんどの環境では、これは大きな問題にはなりません。ただし、インデックスがアプリケーションによって実際に使用されており、ただ容量を取っていることがないよう確認する必要があります。

**Topics**
+ [

## インデックスを作成するときのリレーショナル (SQL) データベースと DynamoDB の相違点
](#SQLtoNoSQL.Indexes.Creating)
+ [

## インデックスのクエリとスキャンをするときのリレーショナル (SQL) データベースと DynamoDB の相違点
](#SQLtoNoSQL.Indexes.QueryAndScan)

## インデックスを作成するときのリレーショナル (SQL) データベースと DynamoDB の相違点
<a name="SQLtoNoSQL.Indexes.Creating"></a>

SQL の `CREATE INDEX` ステートメントを Amazon DynamoDB の `UpdateTable` オペレーションと比較します。

**Topics**
+ [

### SQL を使ってインデックスを作成する
](#SQLtoNoSQL.Indexes.Creating.SQL)
+ [

### DynamoDB でインデックスを作成する
](#SQLtoNoSQL.Indexes.Creating.DynamoDB)

### SQL を使ってインデックスを作成する
<a name="SQLtoNoSQL.Indexes.Creating.SQL"></a>

リレーショナルデータベースのインデックスは、テーブルの異なる列に対して高速にクエリを実行できるデータ構造です。`CREATE INDEX` SQL ステートメントを使用して、既存のテーブルにインデックスが追加し、インデックスを作成する列を指定します。インデックスの作成後は、通常どおりテーブルのデータにクエリを実行できますが、テーブル全体をスキャンする代わりに、テーブルの指定された行を迅速に検索するため、データベースがインデックスを使用することができます。

インデックスの作成後は、データベースが維持します。テーブルのデータを変更した場合は、インデックスが自動的に変更され、テーブル内の変更を反映します。

MySQL では、次のようなインデックスを作成します。

```
CREATE INDEX GenreAndPriceIndex
ON Music (genre, price);
```

### DynamoDB でインデックスを作成する
<a name="SQLtoNoSQL.Indexes.Creating.DynamoDB"></a>

DynamoDB では、同様の目的のために、*セカンダリインデックス*を作成して使用できます。

DynamoDB のインデックスはリレーショナルな対応物とは異なります。セカンダリインデックスを作成する際、そのキー属性 (パーティションキーとソートキー) を指定する必要があります。セカンダリインデックスを作成したら、テーブルと同じように `Query` または `Scan` を実行できます。DynamoDB にはクエリオプティマイザーがないため、セカンダリインデックスは `Query` または `Scan` の場合にのみ使用されます。

DynamoDB では、次の 2 種類のインデックスをサポートしています。
+ グローバルセカンダリインデックス – インデックスのプライマリキーは、テーブルからの任意の 2 つの属性になります。
+ ローカルセカンダリインデックス – インデックスのパーティションキーは、テーブルのパーティションキーと同じである必要があります。ただし、ソートキーは、他の任意の属性にすることができます。

DynamoDB を使えば、セカンダリインデックスのデータは結果的にテーブルと整合性が取れます。テーブルまたはローカルセカンダリインデックスでの強い整合性を持つ `Query` または `Scan` オペレーションをリクエストできます。ただし、グローバルセカンダリインデックスは結果整合性のみをサポートします。

`UpdateTable` オペレーションを使用し、`GlobalSecondaryIndexUpdates` を指定して、既存のテーブルにグローバルセカンダリインデックスを追加できます。

```
{
    TableName: "Music",
    AttributeDefinitions:[
        {AttributeName: "Genre", AttributeType: "S"},
        {AttributeName: "Price", AttributeType: "N"}
    ],
    GlobalSecondaryIndexUpdates: [
        {
            Create: {
                IndexName: "GenreAndPriceIndex",
                KeySchema: [
                    {AttributeName: "Genre", KeyType: "HASH"}, //Partition key
                    {AttributeName: "Price", KeyType: "RANGE"}, //Sort key
                ],
                Projection: {
                    "ProjectionType": "ALL"
                },
                ProvisionedThroughput: {                                // Only specified if using provisioned mode
                    "ReadCapacityUnits": 1,"WriteCapacityUnits": 1
                }
            }
        }
    ]
}
```

`UpdateTable` に以下のパラメータを提供する必要があります。
+ `TableName` – インデックスが関連付けられるテーブル。
+ `AttributeDefinitions` – インデックスのキースキーマ属性用のデータ型。
+ `GlobalSecondaryIndexUpdates` – 作成するインデックスに関する詳細。
  + `IndexName` – インデックスの名前。
  + `KeySchema` – インデックスのプライマリキーに使用する属性。
  + `Projection` – テーブルからインデックスにコピーされる属性。この場合、`ALL` は、すべての属性がコピーされることを意味します。
  + `ProvisionedThroughput (for provisioned tables)` – このインデックスに必要な 1 秒あたりの読み取り/書き込み数。(これは、テーブルのプロビジョニングされたスループット設定とは異なります。) 

このオペレーションの一部は、テーブルから新しいインデックスにデータをバックフィリングすることを含みます。バックフィリング中、テーブルは使用可能なままになります。ただし、インデックスは `Backfilling` 属性が true から false に変わるまで、準備ができていません。`DescribeTable` オペレーションを使用して、この属性を表示できます。

## インデックスのクエリとスキャンをするときのリレーショナル (SQL) データベースと DynamoDB の相違点
<a name="SQLtoNoSQL.Indexes.QueryAndScan"></a>

SQL の SELECT ステートメントを使用したインデックスのクエリとスキャンを Amazon DynamoDB の `Query` および `Scan` オペレーションと比較します。

**Topics**
+ [

### SQL を使ってインデックスのクエリを実行してスキャンする
](#SQLtoNoSQL.Indexes.QueryAndScan.SQL)
+ [

### DynamoDB でインデックスのクエリを実行してスキャンする
](#SQLtoNoSQL.Indexes.QueryAndScan.DynamoDB)

### SQL を使ってインデックスのクエリを実行してスキャンする
<a name="SQLtoNoSQL.Indexes.QueryAndScan.SQL"></a>

リレーショナルデータベースでは、インデックスを直接使用しません。代わりに、`SELECT` ステートメントの発行により、テーブルでクエリを実行し、クエリオプティマイザは任意のインデックスを利用できます。

*クエリオプティマイザ*は、使用できるインデックスを評価し、クエリを高速化するためにそれらを使用できるかを決定するリレーショナルデータベース管理システム (RDBMS) のコンポーネントです。クエリを高速化するためにインデックスが使用できる場合、RDBMS は最初にインデックスにアクセスし、それを使用してテーブルのデータを特定します。

*GenreAndPriceIndex* を使用してパフォーマンスを向上できる SQL ステートメントを次に示します。ここでは、*Music* テーブルに十分なデータがあり、クエリオプティマイザが、テーブル全体にスキャンするのではなく、このインデックスを使用することを前提にします。

```
/* All of the rock songs */

SELECT * FROM Music
WHERE Genre = 'Rock';
```

```
/* All of the cheap country songs */

SELECT Artist, SongTitle, Price FROM Music
WHERE Genre = 'Country' AND Price < 0.50;
```

### DynamoDB でインデックスのクエリを実行してスキャンする
<a name="SQLtoNoSQL.Indexes.QueryAndScan.DynamoDB"></a>

DynamoDB では、テーブルに対して実行するのと同じように、インデックスに対して直接 `Query` および `Scan` オペレーションを実行します。DynamoDB API または [PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html) (SQL 互換のクエリ言語) を使用して、インデックスにクエリやスキャンを実行できます。`TableName` と `IndexName` の両方を指定する必要があります。

以下は、DynamoDB の *GenreAndPriceIndex* に対するいくつかのクエリです。(このインデックスのキースキーマは、*ジャンル*と*価格*で構成されています。)

------
#### [ DynamoDB API ]

```
// All of the rock songs

{
    TableName: "Music",
    IndexName: "GenreAndPriceIndex",
    KeyConditionExpression: "Genre = :genre",
    ExpressionAttributeValues: {
        ":genre": "Rock"
    },
};
```

この例では `ProjectionExpression` を使用して、属性すべてではなく、一部のみを結果に表示することを示します。

```
// All of the cheap country songs

{
    TableName: "Music",
    IndexName: "GenreAndPriceIndex",
    KeyConditionExpression: "Genre = :genre and Price < :price",
    ExpressionAttributeValues: {
        ":genre": "Country",
        ":price": 0.50
    },
    ProjectionExpression: "Artist, SongTitle, Price"
};
```

次に示すのは、*GenreAndPriceIndex* に対するスキャンです。

```
// Return all of the data in the index

{
    TableName:  "Music",
    IndexName: "GenreAndPriceIndex"
}
```

------
#### [ PartiQL for DynamoDB ]

PartiQL では、`Select` ステートメントを使用して、インデックスに対してクエリとスキャンを実行します。

```
// All of the rock songs

SELECT * 
FROM Music.GenreAndPriceIndex
WHERE Genre = 'Rock'
```

```
// All of the cheap country songs

SELECT * 
FROM Music.GenreAndPriceIndex
WHERE Genre = 'Rock' AND Price < 0.50
```

次に示すのは、*GenreAndPriceIndex* に対するスキャンです。

```
// Return all of the data in the index

SELECT *
FROM Music.GenreAndPriceIndex
```

**注記**  
`Select` を使用したコード例については、「[DynamoDB 用の PartiQL select ステートメント](ql-reference.select.md)」を参照してください。

------