

# SQL에서 NoSQL로 전환하는 방법 알아보기
<a name="SQLtoNoSQL"></a>

애플리케이션 개발자라면 RDBMS(관계형 데이터베이스 관리 시스템) 및 SQL(Structured Query Language)을 사용한 경험이 어느 정도 있을 것입니다. Amazon DynamoDB 작업을 시작해 보면 비슷한 점도 많겠지만 다른 점도 상당히 많습니다. *NoSQL*은 가용성과 확장성이 높고 고성능에 최적화된 비관계형 데이터베이스 시스템을 설명하는 데 사용되는 용어입니다. NoSQL 데이터베이스(예: DynamoDB)는 관계형 모델 대신 키 값 페어나 문서 스토리지 같은 대체 모델을 데이터 관리에 사용합니다. 자세한 내용은 [NoSQL이란 무엇입니까?](https://aws.amazon.com/nosql)를 참조하세요.

Amazon DynamoDB는 오픈 소스 SQL 호환 쿼리 언어인 [PartiQL](https://partiql.org/)을 지원합니다. 이 언어를 사용하면 데이터가 저장되는 위치 또는 형식과 관계없이 데이터를 효율적으로 쿼리할 수 있습니다. PartiQL을 사용하면 관계형 데이터베이스의 구조화된 데이터, 개방형 데이터 형식의 반정형 및 중첩 데이터, 행에 따라 다른 속성을 지정할 수 있는 NoSQL 또는 문서 데이터베이스의 스키마 없는 데이터까지도 손쉽게 처리할 수 있습니다. 자세한 내용은 [PartiQL 쿼리 언어](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html)를 참조하세요.

다음 섹션에서는 SQL 문을 그에 상당하는 DynamoDB 작업과 비교 대조하면서 공통 데이터베이스 작업에 대해 설명합니다.

**참고**  
이 섹션의 SQL 예제는 MySQL RDBMS와 호환됩니다.  
이 섹션의 DynamoDB 예제는 DynamoDB 작업의 이름과 함께 JSON 형식의 해당 작업 파라미터를 보여 줍니다.

**Topics**
+ [관계형(SQL)과 NoSQL 중에서 선택](SQLtoNoSQL.WhyDynamoDB.md)
+ [관계형(SQL) 데이터베이스 및 DynamoDB 액세스 비교](SQLtoNoSQL.Accessing.md)
+ [테이블 생성 시 관계형(SQL) 데이터베이스 및 DynamoDB 비교](SQLtoNoSQL.CreateTable.md)
+ [관계형(SQL) 데이터베이스 및 DynamoDB에서 테이블 정보 가져오기 비교](SQLtoNoSQL.GetTableInfo.md)
+ [테이블에 데이터를 쓸 때의 관계형(SQL) 데이터베이스와 DynamoDB 비교](SQLtoNoSQL.WriteData.md)
+ [테이블에서 데이터를 읽을 때의 관계형(SQL) 데이터베이스와 DynamoDB 비교](SQLtoNoSQL.ReadData.md)
+ [인덱스 관리 시 관계형(SQL) 데이터베이스와 DynamoDB 비교](SQLtoNoSQL.Indexes.md)
+ [테이블에서 데이터를 수정할 때 관계형(SQL) 데이터베이스와 DynamoDB 비교](SQLtoNoSQL.UpdateData.md)
+ [테이블에서 데이터를 삭제할 때 관계형(SQL) 데이터베이스와 DynamoDB 비교](SQLtoNoSQL.DeleteData.md)
+ [테이블 제거 시 관계형(SQL) 데이터베이스와 DynamoDB 비교](SQLtoNoSQL.RemoveTable.md)

# 관계형(SQL)과 NoSQL 중에서 선택
<a name="SQLtoNoSQL.WhyDynamoDB"></a>

오늘날의 애플리케이션의 요구 사항은 그 어느 때보다 까다롭습니다. 예를 들어 온라인 게임은 소수의 사용자와 아주 작은 양의 데이터만으로 시작될 수 있습니다. 하지만 게임이 성공을 거두면 기본 데이터베이스 시스템의 리소스를 가볍게 초과할 수 있습니다. 웹 기반 애플리케이션의 동시 사용자가 수백 명, 수천 명 또는 수백만 명에 이르고, 매일 테라바이트 규모의 데이터가 새로 생성되는 경우는 드물지 않습니다. 이런 애플리케이션의 데이터베이스는 초당 수만(혹은 수십만) 건의 읽기 및 쓰기를 처리해야 합니다.

Amazon DynamoDB는 이런 종류의 워크로드에 적합합니다. 개발자는 작은 크기로 시작하고, 애플리케이션의 인기가 높아짐에 따라 사용률을 점차로 늘릴 수 있습니다. DynamoDB는 대량의 데이터와 매우 많은 수의 사용자를 처리할 수 있도록 크기를 원활하게 조정합니다.

기존 관계형 데이터베이스 모델링과 이를 DynamoDB에 맞게 조정하는 방법에 대한 자세한 내용은 [DynamoDB의 관계형 데이터 모델링 모범 사례](bp-relational-modeling.md) 섹션을 참조하세요.

다음 표에서는 관계형 데이터베이스 관리 시스템(RDBMS)과 DynamoDB의 몇 가지 중요한 차이점을 보여줍니다.


****  

| 기능 | 관계형 데이터베이스 관리 시스템(RDBMS) | Amazon DynamoDB | 
| --- | --- | --- | 
| 최적의 워크로드 | 임시 쿼리, 데이터 웨어하우징, OLAP(Online Analytical Processing). | 소셜 네트워크, 게이밍, 미디어 공유, IoT(사물 인터넷) 등 웹 규모의 애플리케이션입니다. | 
| 데이터 모델 | 관계형 모델의 경우 데이터가 테이블, 행 및 열로 정규화되는 잘 정의된 스키마가 필요합니다. 뿐만 아니라 테이블, 행, 인덱스 및 기타 데이터베이스 간의 모든 관계가 정의됩니다. | DynamoDB는 스키마가 없습니다. 각 테이블에는 각각의 데이터 항목을 고유하게 식별하는 기본 키가 있어야 하지만 키가 아닌 다른 속성에는 비슷한 제한이 없습니다. DynamoDB는 JSON 문서를 비롯한 정형 또는 반정형 데이터를 관리할 수 있습니다. | 
| 데이터 액세스 | SQL은 데이터 저장과 검색을 위한 표준입니다. 관계형 데이터베이스는 데이터베이스 중심 애플리케이션 개발을 단순화하는 풍부한 도구 세트를 제공하지만 이 도구 모두가 SQL을 사용하는 것은 아닙니다. | AWS Management Console, AWS CLI 또는 NoSQL WorkBench를 사용하여 DynamoDB 작업을 수행하고 임시 태스크를 수행할 수 있습니다. SQL 호환 쿼리 언어인 [PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html)을 사용하여 DynamoDB에서 데이터를 선택, 삽입, 업데이트, 삭제할 수 있습니다. 애플리케이션은 AWS 소프트웨어 개발 키트(SDK)를 활용하여 객체 기반, 문서 중심 또는 하위 수준 인터페이스를 통해 DynamoDB 작업을 할 수 있습니다. | 
| 성능: | 관계형 데이터베이스는 스토리지에 최적화되어 있으므로 일반적으로 성능은 디스크 하위 시스템에 좌우됩니다. 개발자와 데이터베이스 관리자는 성능 극대화를 위해 쿼리, 인덱스 및 테이블 구조를 최적화해야 합니다. | DynamoDB는 컴퓨팅에 최적화되어 있기 때문에 성능은 주로 기본 하드웨어와 네트워크 대기 시간에 달려 있습니다. 관리형 서비스인 DynamoDB는 사용자와 사용자 애플리케이션이 이런 구현 세부 사항에 영향을 받지 않도록 보호하여 견고한 고성능 애플리케이션을 설계하고 구축하는 데 집중할 수 있게 합니다. | 
| 규모 조정 | 보다 빠른 하드웨어를 통한 확장은 더할 나위 없이 쉽습니다. 데이터베이스 테이블을 분산 시스템의 여러 호스트에 배치하는 것도 가능하지만 여기에는 추가 투자가 필요합니다. 관계형 데이터베이스는 파일 숫자와 크기에 최대치가 있어 이것이 확장성의 상한선이 됩니다. | DynamoDB는 분산된 하드웨어 클러스터를 사용하여 확장하도록 설계되었습니다. 이런 설계 덕에 지연 시간 증가 없는 처리 능력 증대가 가능합니다. 고객이 처리량 요구 사항을 지정하면 DynamoDB는 충분한 리소스를 할당하여 이 요구 사항을 충족합니다. 테이블당 항목 수에 상한선이 없고, 테이블의 총 크기 역시 마찬가지입니다. | 

# 관계형(SQL) 데이터베이스 및 DynamoDB 액세스 비교
<a name="SQLtoNoSQL.Accessing"></a>

애플리케이션에서 데이터베이스에 액세스할 수 있으려면 애플리케이션에서 해당 데이터베이스를 사용할 수 있도록 애플리케이션이 *인증*되어야 합니다. 애플리케이션은 해당 권한을 가진 작업만 수행할 수 있도록 *권한 부여*되어야 합니다.

다음 다이어그램은 관계형 데이터베이스 및 Amazon DynamoDB와의 클라이언트 상호 작용을 보여줍니다.

![\[관계형 및 NoSQL 데이터베이스와의 상호 작용\]](http://docs.aws.amazon.com/ko_kr/amazondynamodb/latest/developerguide/images/SQLtoNoSQL.png)


다음 표에는 클라이언트 상호 작용 작업에 대한 자세한 내용이 나와 있습니다.


****  

| 기능 | 관계형 데이터베이스 관리 시스템(RDBMS) | Amazon DynamoDB | 
| --- | --- | --- | 
| 데이터베이스 액세스 도구 |  대부분의 관계형 데이터베이스는 명령줄 인터페이스(CLI)를 제공하므로 특별 SQL 문을 입력하고 결과를 즉시 확인할 수 있습니다.  | 대부분의 경우에는 애플리케이션 코드를 작성합니다. AWS Management Console, AWS Command Line Interface(AWS CLI) 또는 NoSQL Workbench를 사용하여 DynamoDB에 임시 요청을 보내고 결과를 볼 수도 있습니다. SQL 호환 쿼리 언어인 [PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html)을 사용하여 DynamoDB에서 데이터를 선택, 삽입, 업데이트, 삭제할 수 있습니다. | 
| 데이터베이스에 연결 | 애플리케이션은 데이터베이스와의 네트워크 연결을 구축하고 유지합니다. 애플리케이션은 종료될 때 연결을 끊습니다. | DynamoDB는 웹 서비스이며, 해당 데이터베이스와 상호 작용은 상태 비저장입니다. 애플리케이션은 지속적인 네트워크 연결을 유지할 필요가 없습니다. 그 대신 DynamoDB와의 상호 작용은 HTTP(S) 요청 및 응답을 사용하여 이루어집니다. | 
| Authentication | 애플리케이션은 인증되기 전에는 데이터베이스에 연결할 수 없습니다. RDBMS는 직접 인증을 수행하거나 호스트 운영 체제 또는 디렉터리 서비스에 이 작업을 오프로드할 수 있습니다. | DynamoDB에 대한 모든 요청에는 해당 특정 요청을 인증하는 암호화 서명이 함께 제공되어야 합니다. AWS SDK는 서명 및 서명 요청을 생성하는 데 필요한 모든 로직을 제공합니다. 자세한 내용은 AWS 일반 참조의 [AWS API 요청 서명](https://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html)을 참조하세요. | 
| 권한 부여 | 애플리케이션은 권한을 부여받은 작업만 수행할 수 있습니다. 데이터베이스 관리자나 애플리케이션 소유자는 SQL GRANT 및 REVOKE 문을 사용하여 (테이블 등의) 데이터베이스 객체, (테이블 내의 행 등의) 데이터 또는 특정 SQL 문 발행 능력에 대한 액세스를 제어할 수 있습니다. | DynamoDB에서는 AWS Identity and Access Management(IAM)에 의해 권한 부여가 처리됩니다. 테이블과 같은 DynamoDB 리소스에 대한 권한을 부여하는 IAM 정책을 작성한 다음 사용자 및 역할이 해당 정책을 사용하도록 허용할 수 있습니다. IAM은 DynamoDB 테이블의 개별 항목에 대한 액세스를 세부적으로 제어할 수도 있습니다. 자세한 내용은 [Amazon DynamoDB의 Identity and Access Management](security-iam.md) 섹션을 참조하세요. | 
| 요청 전송 | 애플리케이션은 수행하려는 모든 데이터베이스 작업에 대해 SQL 문을 발행합니다. SQL 문을 수신하면 RDBMS는 구문을 확인하고 작업 수행 계획을 생성한 다음 계획을 실행합니다. | 애플리케이션은 HTTP(S) 요청을 DynamoDB에 보냅니다. 요청에는 수행할 DynamoDB 작업의 이름과 함께 파라미터가 포함되어 있습니다. DynamoDB는 요청을 즉시 실행합니다. | 
| 응답 수신 | RDBMS는 SQL 문의 결과를 반환합니다. 오류가 있는 경우, RDBMS는 오류 상태와 메시지를 반환합니다. | DynamoDB는 작업 결과가 포함된 HTTP(S) 응답을 반환합니다. 오류가 있는 경우 DynamoDB는 HTTP 오류 상태 및 메시지를 반환합니다. | 

# 테이블 생성 시 관계형(SQL) 데이터베이스 및 DynamoDB 비교
<a name="SQLtoNoSQL.CreateTable"></a>

테이블은 관계형 데이터베이스와 Amazon DynamoDB의 기본 데이터 구조입니다. 관계형 데이터베이스 관리 시스템(RDBMS)에서는 테이블을 생성할 때 테이블의 스키마를 정의해야 합니다. 반면 DynamoDB 테이블은 스키마가 없습니다. 즉, 테이블을 생성할 때 기본 키 외에는 추가 속성이나 데이터 형식을 정의할 필요가 없습니다.

다음 섹션에서는 SQL을 사용하여 테이블을 생성하는 방법과 DynamoDB를 사용하여 테이블을 생성하는 방법을 비교합니다.

**Topics**
+ [SQL에서 테이블 생성](#SQLtoNoSQL.CreateTable.SQL)
+ [DynamoDB에서 테이블 생성](#SQLtoNoSQL.CreateTable.DynamoDB)

## SQL에서 테이블 생성
<a name="SQLtoNoSQL.CreateTable.SQL"></a>

SQL에서는 다음 예에 나온 것처럼 `CREATE TABLE` 문을 사용하여 테이블을 생성합니다.

```
CREATE TABLE Music (
    Artist VARCHAR(20) NOT NULL,
    SongTitle VARCHAR(30) NOT NULL,
    AlbumTitle VARCHAR(25),
    Year INT,
    Price FLOAT,
    Genre VARCHAR(10),
    Tags TEXT,
    PRIMARY KEY(Artist, SongTitle)
);
```

이 테이블의 기본 키는 *Artist* 및 *SongTitle*로 구성됩니다.

테이블의 모든 열과 데이터 형식 및 테이블의 기본 키를 정의해야 합니다. (필요할 경우, `ALTER TABLE` 문을 사용하여 나중에 이 정의를 변경할 수 있습니다.)

많은 SQL 구현에서는 `CREATE TABLE` 문의 일부로 테이블의 스토리지 사양을 정의할 수 있습니다. 달리 지정하지 않는 한 테이블은 기본 스토리지 설정으로 생성됩니다. 프로덕션 환경에서 데이터베이스 관리자는 최적의 스토리지 파라미터 결정을 도울 수 있습니다.

## DynamoDB에서 테이블 생성
<a name="SQLtoNoSQL.CreateTable.DynamoDB"></a>

다음 예에 나온 것처럼 `CreateTable` 작업을 사용하여 프로비저닝된 모드 테이블을 생성하고 파라미터를 지정합니다.

```
{
    TableName : "Music",
    KeySchema: [
        {
            AttributeName: "Artist",
            KeyType: "HASH" //Partition key
        },
        {
            AttributeName: "SongTitle",
            KeyType: "RANGE" //Sort key
        }
    ],
    AttributeDefinitions: [
        {
            AttributeName: "Artist",
            AttributeType: "S"
        },
        {
            AttributeName: "SongTitle",
            AttributeType: "S"
        }
    ],
    ProvisionedThroughput: {       // Only specified if using provisioned mode
        ReadCapacityUnits: 1,
        WriteCapacityUnits: 1
    }
}
```

이 테이블의 기본 키는 *Artist*(파티션 키)와 *SongTitle*(정렬 키)로 구성됩니다.

다음 파라미터를 `CreateTable`에 입력해야 합니다.
+ `TableName` - 테이블 이름
+ `KeySchema` - 기본 키에 사용되는 속성. 자세한 내용은 [테이블, 항목 및 속성](HowItWorks.CoreComponents.md#HowItWorks.CoreComponents.TablesItemsAttributes) 및 [프라이머리 키](HowItWorks.CoreComponents.md#HowItWorks.CoreComponents.PrimaryKey) 섹션을 참조하세요.
+ `AttributeDefinitions` - 키 스키마 속성의 데이터 형식
+ `ProvisionedThroughput (for provisioned tables)` - 이 테이블에 필요한 초당 읽기 및 쓰기 수. DynamoDB는 처리량 요구 사항이 항상 충족되도록 충분한 스토리지 및 시스템 리소스를 남겨 둡니다. 필요할 경우, `UpdateTable` 작업을 사용하여 나중에 이를 변경할 수 있습니다. 스토리지 할당이 전적으로 DynamoDB에 의해 관리되기 때문에 테이블의 스토리지 요구 사항을 지정할 필요가 없습니다.

# 관계형(SQL) 데이터베이스 및 DynamoDB에서 테이블 정보 가져오기 비교
<a name="SQLtoNoSQL.GetTableInfo"></a>

테이블이 사양에 따라 생성되었음을 확인할 수 있습니다. 관계형 데이터베이스에서는 테이블 스키마가 모두 표시됩니다. Amazon DynamoDB 테이블은 스키마가 없으므로 기본 키 속성만 표시됩니다.

**Topics**
+ [SQL에서 테이블에 대한 정보 가져오기](#SQLtoNoSQL.GetTableInfo.SQL)
+ [DynamoDB에서 테이블에 대한 정보 가져오기](#SQLtoNoSQL.GetTableInfo.DynamoDB)

## SQL에서 테이블에 대한 정보 가져오기
<a name="SQLtoNoSQL.GetTableInfo.SQL"></a>

대부분의 관계형 데이터베이스 관리 시스템(RDBMS)에서는 열, 데이터 형식, 기본 키 정의 등과 같은 테이블 구조를 설명할 수 있습니다. SQL에서는 이 작업을 하는 표준적 방법이 없습니다. 다만 많은 데이터베이스 시스템은 `DESCRIBE` 명령을 제공합니다. 다음은 MySQL 예제입니다.

```
DESCRIBE Music;
```

이는 모든 열 이름, 데이터 형식, 크기와 함께 테이블의 구조를 반환합니다.

```
+------------+-------------+------+-----+---------+-------+
| Field      | Type        | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| Artist     | varchar(20) | NO   | PRI | NULL    |       |
| SongTitle  | varchar(30) | NO   | PRI | NULL    |       |
| AlbumTitle | varchar(25) | YES  |     | NULL    |       |
| Year       | int(11)     | YES  |     | NULL    |       |
| Price      | float       | YES  |     | NULL    |       |
| Genre      | varchar(10) | YES  |     | NULL    |       |
| Tags       | text        | YES  |     | NULL    |       |
+------------+-------------+------+-----+---------+-------+
```

이 테이블의 기본 키는 *Artist* 및 *SongTitle*로 구성됩니다.

## DynamoDB에서 테이블에 대한 정보 가져오기
<a name="SQLtoNoSQL.GetTableInfo.DynamoDB"></a>

DynamoDB에는 이와 비슷한 `DescribeTable` 작업이 있습니다. 이때는 테이블 이름 파라미터만 있으면 됩니다.

```
{
    TableName : "Music"
}
```

`DescribeTable`의 회신은 다음과 같습니다.

```
{
  "Table": {
    "AttributeDefinitions": [
      {
        "AttributeName": "Artist",
        "AttributeType": "S"
      },
      {
        "AttributeName": "SongTitle",
        "AttributeType": "S"
      }
    ],
    "TableName": "Music",
    "KeySchema": [
      {
        "AttributeName": "Artist",
        "KeyType": "HASH"  //Partition key
      },
      {
        "AttributeName": "SongTitle",
        "KeyType": "RANGE"  //Sort key
      }
    ],

    ...
```

`DescribeTable`은 또한 테이블의 인덱스, 할당된 처리량 설정, 대략적인 항목 카운트 및 기타 메타데이터에 관한 정보를 반환합니다.

# 테이블에 데이터를 쓸 때의 관계형(SQL) 데이터베이스와 DynamoDB 비교
<a name="SQLtoNoSQL.WriteData"></a>

관계형 데이터베이스 테이블에는 데이터의 *행*이 포함됩니다. 행은 *열*로 구성됩니다. Amazon DynamoDB 테이블에는 *항목*이 포함됩니다. 항목은 *속성*으로 구성됩니다.

이 섹션에서는 테이블에 하나의 행(또는 항목)을 쓰는 방법을 설명합니다.

**Topics**
+ [SQL에서 테이블에 데이터 쓰기](#SQLtoNoSQL.WriteData.SQL)
+ [DynamoDB에서 테이블에 데이터 쓰기](#SQLtoNoSQL.WriteData.DynamoDB)

## SQL에서 테이블에 데이터 쓰기
<a name="SQLtoNoSQL.WriteData.SQL"></a>

관계형 데이터베이스의 테이블은 행과 열로 이루어진 2차원 데이터 구조입니다. 일부 데이터베이스 관리 시스템은 보통 기본 JSON 또는 XML 데이터 형식을 사용하여 반정형 데이터 지원도 제공합니다. 하지만 구현의 세부적 내용은 공급업체마다 다릅니다.

SQL에서는 `INSERT` 문을 사용하여 테이블에 행을 추가합니다.

```
INSERT INTO Music
    (Artist, SongTitle, AlbumTitle,
    Year, Price, Genre,
    Tags)
VALUES(
    'No One You Know', 'Call Me Today', 'Somewhat Famous',
    2015, 2.14, 'Country',
    '{"Composers": ["Smith", "Jones", "Davis"],"LengthInSeconds": 214}'
);
```

이 테이블의 기본 키는 *Artist* 및 *SongTitle*로 구성됩니다. 이 열들의 값을 지정해야 합니다.

**참고**  
이 예제에서는 *Tags* 열을 사용하여 *Music* 테이블의 노래에 대한 반정형 데이터를 저장합니다. *Tags* 열은 TEXT 형식으로 정의되었으며 MySQL에 최대 65,535자를 저장할 수 있습니다.

## DynamoDB에서 테이블에 데이터 쓰기
<a name="SQLtoNoSQL.WriteData.DynamoDB"></a>

Amazon DynamoDB에서는 DynamoDB API나 [PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html)(SQL 호환 쿼리 언어)을 사용하여 테이블에 항목을 추가할 수 있습니다.

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

DynamoDB API에서는 `PutItem` 작업을 사용하여 테이블에 항목을 추가합니다.

```
{
    TableName: "Music",
    Item: {
        "Artist":"No One You Know",
        "SongTitle":"Call Me Today",
        "AlbumTitle":"Somewhat Famous",
        "Year": 2015,
        "Price": 2.14,
        "Genre": "Country",
        "Tags": {
            "Composers": [
                  "Smith",
                  "Jones",
                  "Davis"
            ],
            "LengthInSeconds": 214
        }
    }
}
```

이 테이블의 기본 키는 *Artist* 및 *SongTitle*로 구성됩니다. 이 속성들의 값을 지정해야 합니다.

다음은 이 `PutItem` 예제에 관해 알아야 할 주요 사항입니다.
+ DynamoDB는 JSON을 사용하여 문서에 대한 기본 지원을 제공합니다. 따라서 DynamoDB는 *Tags* 같은 반정형 데이터를 저장하는 데 적합합니다. JSON 문서 안에서 데이터를 가져오고 조작할 수도 있습니다.
+ *Music* 테이블에는 기본 키(*Artist* 및 *SongTitle*) 외에는 미리 정의된 속성이 없습니다.
+ 대부분의 SQL 데이터베이스는 트랜잭션 지향적입니다. `INSERT` 문을 발행하더라도 `COMMIT` 문을 발행하기 전까지는 데이터 수정이 영구적이지 않습니다. Amazon DynamoDB의 경우, DynamoDB가 HTTP 200 상태 코드(`OK`)로 응답하면 `PutItem` 작업의 결과가 영구적으로 적용됩니다.

다음은 몇 가지 다른 `PutItem` 예제입니다.

```
{
    TableName: "Music",
    Item: {
        "Artist": "No One You Know",
        "SongTitle": "My Dog Spot",
        "AlbumTitle":"Hey Now",
        "Price": 1.98,
        "Genre": "Country",
        "CriticRating": 8.4
    }
}
```

```
{
    TableName: "Music",
    Item: {
        "Artist": "No One You Know",
        "SongTitle": "Somewhere Down The Road",
        "AlbumTitle":"Somewhat Famous",
        "Genre": "Country",
        "CriticRating": 8.4,
        "Year": 1984
    }
}
```

```
{
    TableName: "Music",
    Item: {
        "Artist": "The Acme Band",
        "SongTitle": "Still In Love",
        "AlbumTitle":"The Buck Starts Here",
        "Price": 2.47,
        "Genre": "Rock",
        "PromotionInfo": {
            "RadioStationsPlaying":[
                 "KHCR", "KBQX", "WTNR", "WJJH"
            ],
            "TourDates": {
                "Seattle": "20150625",
                "Cleveland": "20150630"
            },
            "Rotation": "Heavy"
        }
    }
}
```

```
{
    TableName: "Music",
    Item: {
        "Artist": "The Acme Band",
        "SongTitle": "Look Out, World",
        "AlbumTitle":"The Buck Starts Here",
        "Price": 0.99,
        "Genre": "Rock"
    }
}
```

**참고**  
DynamoDB는 `PutItem` 외에도 여러 항목을 동시에 쓰는 `BatchWriteItem` 작업을 지원합니다.

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

PartiQL에서는 PartiQL `Insert` 문을 사용하여 `ExecuteStatement` 작업을 통해 테이블에 항목을 추가합니다.

```
INSERT into Music value {  
    'Artist': 'No One You Know',
    'SongTitle': 'Call Me Today',
    'AlbumTitle': 'Somewhat Famous',
    'Year' : '2015',
    'Genre' : 'Acme'
}
```

이 테이블의 기본 키는 *Artist* 및 *SongTitle*로 구성됩니다. 이 속성들의 값을 지정해야 합니다.

**참고**  
`Insert` 및 `ExecuteStatement`를 사용하는 코드 예제는 [DynamoDB의 PartiQL insert 문](ql-reference.insert.md) 섹션을 참조하세요.

------

# 테이블에서 데이터를 읽을 때의 관계형(SQL) 데이터베이스와 DynamoDB 비교
<a name="SQLtoNoSQL.ReadData"></a>

SQL에서는 `SELECT` 문을 사용하여 테이블에서 하나 이상의 항목을 가져올 수 있습니다. `WHERE` 절을 사용하여 반환되는 데이터를 결정합니다.

한편, Amazon DynamoDB를 사용하는 경우 데이터를 읽기 위해 다음과 같은 작업이 수행됩니다.
+ `ExecuteStatement`는 테이블에서 단일 또는 여러 개의 항목을 가져옵니다. `BatchExecuteStatement`는 단일 작업으로 서로 다른 테이블에서 여러 항목을 가져옵니다. 이 두 작업 모두 SQL 호환 쿼리 언어 [PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html)을 사용합니다.
+ `GetItem` - 테이블에서 단일 항목을 가져옵니다. 이는 항목의 물리적 위치에 대한 직접 액세스를 제공하기 때문에 단일 항목을 읽는 가장 효율적인 방법입니다. (DynamoDB도 단일 작업으로 최대 100개의 `GetItem` 호출을 수행할 수 있는 `BatchGetItem` 작업을 제공합니다.)
+ `Query` - 특정 파티션 키가 있는 항목을 모두 가져옵니다. 이러한 항목 안에서 키를 정렬하고 데이터의 하위 집합만 가져오도록 조건을 적용할 수 있습니다. `Query`는 데이터가 저장된 파티션에 대한 빠르고 효율적인 액세스를 제공합니다. (자세한 내용은 [DynamoDB의 파티션 및 데이터 배포](HowItWorks.Partitions.md) 섹션을 참조하세요.)
+ `Scan` - 지정한 테이블의 모든 항목을 가져옵니다. (이 작업은 시스템 리소스를 많이 사용할 수 있으므로 큰 테이블에는 사용해서는 안 됩니다.)

**참고**  
관계형 데이터베이스의 경우, `SELECT` 문을 사용하여 여러 테이블의 데이터를 조인하고 결과를 반환할 수 있습니다. 조인은 관계형 모델의 기초입니다. 조인의 효율적 실행을 위해서는 데이터베이스와 그 애플리케이션의 성능을 지속적으로 튜닝해야 합니다. DynamoDB는 비관계형 NoSQL 데이터베이스로서 테이블 조인을 지원하지 않습니다. 그 대신 애플리케이션은 한 번에 한 테이블의 데이터를 읽습니다.

다음 섹션에서는 다양한 데이터 읽기 사용 사례를 설명하고, 관계형 데이터베이스와 DynamoDB로 이런 작업을 수행하는 방법을 살펴봅니다.

**Topics**
+ [프라이머리 키를 사용하여 항목 읽기 비교](SQLtoNoSQL.ReadData.SingleItem.md)
+ [테이블 쿼리 비교](SQLtoNoSQL.ReadData.Query.md)
+ [테이블 스캔 비교](SQLtoNoSQL.ReadData.Scan.md)

# 프라이머리 키를 사용하여 항목 읽기 비교
<a name="SQLtoNoSQL.ReadData.SingleItem"></a>

데이터베이스에 대한 공통적인 액세스 패턴 중 하나는 한 테이블에서 단일 항목을 읽어오는 것입니다. 원하는 항목의 기본 키를 지정해야 합니다.

**Topics**
+ [SQL에서 항목의 프라이머리 키를 사용하여 항목 읽기](#SQLtoNoSQL.ReadData.SingleItem.SQL)
+ [DynamoDB에서 항목의 프라이머리 키를 사용하여 항목 읽기](#SQLtoNoSQL.ReadData.SingleItem.DynamoDB)

## SQL에서 항목의 프라이머리 키를 사용하여 항목 읽기
<a name="SQLtoNoSQL.ReadData.SingleItem.SQL"></a>

SQL에서는 `SELECT` 문을 사용하여 테이블에서 데이터를 가져옵니다. 결과에 하나 이상의 열(또는 `*` 연산자를 사용하는 경우 모든 열)이 포함되도록 요청할 수 있습니다. `WHERE` 절은 반환할 행을 결정합니다.

다음은 *Music* 테이블에서 단일 행을 가져오는 `SELECT` 문입니다. `WHERE` 절은 기본 키 값을 지정합니다.

```
SELECT *
FROM Music
WHERE Artist='No One You Know' AND SongTitle = 'Call Me Today'
```

이 쿼리를 수정하여 열의 하위 집합만 검색할 수 있습니다.

```
SELECT AlbumTitle, Year, Price
FROM Music
WHERE Artist='No One You Know' AND SongTitle = 'Call Me Today'
```

이 테이블의 프라이머리 키는 *Artist* 및 *SongTitle*로 구성되어 있다는 점에 유의하세요.

## DynamoDB에서 항목의 프라이머리 키를 사용하여 항목 읽기
<a name="SQLtoNoSQL.ReadData.SingleItem.DynamoDB"></a>

Amazon DynamoDB에서는 DynamoDB API나 [PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html)(SQL 호환 쿼리 언어)을 사용하여 테이블에서 항목을 읽을 수 있습니다.

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

DynamoDB API에서는 `PutItem` 작업을 사용하여 테이블에 항목을 추가합니다.

DynamoDB는 항목을 해당 프라이머리 키를 기준으로 가져오기 위한 `GetItem` 작업을 제공합니다. `GetItem`은 항목의 물리적 위치에 대한 직접 액세스를 제공하므로 매우 효율적입니다. (자세한 내용은 [DynamoDB의 파티션 및 데이터 배포](HowItWorks.Partitions.md) 섹션을 참조하세요.)

기본적으로 `GetItem`은 모든 속성과 함께 전체 항목을 반환합니다.

```
{
    TableName: "Music",
    Key: {
        "Artist": "No One You Know",
        "SongTitle": "Call Me Today"
    }
}
```

속성의 일부만 반환하는 `ProjectionExpression` 파라미터를 추가할 수 있습니다.

```
{
    TableName: "Music",
    Key: {
        "Artist": "No One You Know",
        "SongTitle": "Call Me Today"
    },
    "ProjectionExpression": "AlbumTitle, Year, Price"
}
```

이 테이블의 프라이머리 키는 *Artist* 및 *SongTitle*로 구성되어 있다는 점에 유의하세요.

DynamoDB `GetItem` 작업은 매우 효율적입니다. 프라이머리 키 값을 사용하여 해당 항목의 정확한 스토리지 위치를 확인하고 그 위치에서 직접 항목을 가져옵니다. SQL `SELECT` 문도 기본 키 값을 기준으로 항목을 가져오는 경우에는 마찬가지로 효율적입니다.

SQL `SELECT` 문은 다양한 쿼리 및 테이블 스캔을 지원합니다. DynamoDB는 [테이블 쿼리 비교](SQLtoNoSQL.ReadData.Query.md) 및 [테이블 스캔 비교](SQLtoNoSQL.ReadData.Scan.md)에 설명된 대로 `Query` 및 `Scan` 작업을 통해 이와 비슷한 기능을 제공합니다.

SQL `SELECT` 문은 테이블 조인을 수행하여 한 번에 여러 테이블에서 데이터를 가져올 수 있습니다. 조인은 데이터베이스 테이블들이 정규화되어 있고 테이블 간 관계가 명확한 경우에 가장 효과적입니다. 그러나 하나의 `SELECT` 문에서 지나치게 많은 테이블을 조인하는 경우, 애플리케이션 성능이 영향을 받을 수 있습니다. 이런 문제는 데이터베이스 복제, 구체화된 보기 또는 쿼리 다시 쓰기를 사용하여 해결할 수 있습니다.

DynamoDB는 비관계형 데이터베이스로, 테이블 조인을 지원하지 않습니다. 기존 애플리케이션을 관계형 데이터베이스에서 DynamoDB로 마이그레이션하는 경우, 조인의 필요성을 제거하기 위해 데이터 모델을 비정규화해야 합니다.

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

PartiQL에서는 PartiQL `Select` 문을 사용하여 `ExecuteStatement` 작업을 통해 테이블에서 항목을 읽습니다.

```
SELECT AlbumTitle, Year, Price
FROM Music
WHERE Artist='No One You Know' AND SongTitle = 'Call Me Today'
```

이 테이블의 프라이머리 키는 Artist 및 SongTitle로 구성되어 있다는 점에 유의하세요.

**참고**  
 Select PartiQL 문은 DynamoDB 테이블을 쿼리하거나 스캔하는 데에도 사용할 수 있습니다.

`Select` 및 `ExecuteStatement`를 사용하는 코드 예제는 [DynamoDB의 PartiQL select 문](ql-reference.select.md) 섹션을 참조하세요.

------

# 테이블 쿼리 비교
<a name="SQLtoNoSQL.ReadData.Query"></a>

또 다른 공통적인 액세스 패턴은 쿼리 기준에 기반하여 한 테이블에서 복수의 항목을 읽어오는 것입니다.

**Topics**
+ [SQL에서 테이블 쿼리](#SQLtoNoSQL.ReadData.Query.SQL)
+ [DynamoDB에서 테이블 쿼리](#SQLtoNoSQL.ReadData.Query.DynamoDB)

## SQL에서 테이블 쿼리
<a name="SQLtoNoSQL.ReadData.Query.SQL"></a>

SQL `SELECT` 문을 사용하여 키 열, 키 이외 열 또는 임의의 조합에서 쿼리를 수행할 수 있습니다. 다음 예제와 같이 `WHERE` 절은 반환되는 행을 결정합니다.

```
/* Return a single song, by primary key */

SELECT * FROM Music
WHERE Artist='No One You Know' AND SongTitle = 'Call Me Today';
```

```
/* Return all of the songs by an artist */

SELECT * FROM Music
WHERE Artist='No One You Know';
```

```
/* Return all of the songs by an artist, matching first part of title */

SELECT * FROM Music
WHERE Artist='No One You Know' AND SongTitle LIKE 'Call%';
```

```
/* Return all of the songs by an artist, only if the price is less than 1.00 */

SELECT * FROM Music
WHERE Artist='No One You Know'
AND Price < 1.00;
```

이 테이블의 프라이머리 키는 *Artist* 및 *SongTitle*로 구성되어 있다는 점에 유의하세요.

## DynamoDB에서 테이블 쿼리
<a name="SQLtoNoSQL.ReadData.Query.DynamoDB"></a>

Amazon DynamoDB에서는 DynamoDB API나 [PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html)(SQL 호환 쿼리 언어)을 사용하여 테이블에서 항목을 쿼리할 수 있습니다.

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

Amazon DynamoDB의 `Query` 작업을 사용해도 비슷한 방법으로 데이터를 가져올 수 있습니다. `Query` 작업은 데이터가 저장된 물리적 위치에 대한 빠르고 효율적인 액세스를 제공합니다. 자세한 내용은 [DynamoDB의 파티션 및 데이터 배포](HowItWorks.Partitions.md) 섹션을 참조하세요.

테이블 또는 보조 인덱스와 함께 `Query`를 사용할 수 있습니다. 파티션 키 값에는 등식 조건을 지정해야 하며 지정된 경우 정렬 키 속성에 대해 다른 조건을 선택적으로 지정할 수 있습니다.

`KeyConditionExpression` 파라미터는 쿼리하려는 키 값을 지정합니다. 선택 사항인 `FilterExpression`을 사용하면 반환 전에 일정 항목을 결과에서 제거할 수 있습니다.

DynamoDB에서는 `ExpressionAttributeValues`를 표현식 파라미터(`KeyConditionExpression`, `FilterExpression` 등)에서 자리 표시자로 사용해야 합니다. 이는 런타임에 실제 값을 `SELECT` 문으로 대체하는 관계형 데이터베이스의 *바인드 변수* 사용과 유사합니다.

이 테이블의 프라이머리 키는 *Artist* 및 *SongTitle*로 구성되어 있다는 점에 유의하세요.

다음은 몇 가지 DynamoDB `Query` 예제입니다.

```
// Return a single song, by primary key

{
    TableName: "Music",
    KeyConditionExpression: "Artist = :a and SongTitle = :t",
    ExpressionAttributeValues: {
        ":a": "No One You Know",
        ":t": "Call Me Today"
    }
}
```

```
// Return all of the songs by an artist

{
    TableName: "Music",
    KeyConditionExpression: "Artist = :a",
    ExpressionAttributeValues: {
        ":a": "No One You Know"
    }
}
```

```
// Return all of the songs by an artist, matching first part of title

{
    TableName: "Music",
    KeyConditionExpression: "Artist = :a and begins_with(SongTitle, :t)",
    ExpressionAttributeValues: {
        ":a": "No One You Know",
        ":t": "Call"
    }
}
```

```
// Return all of the songs by an artist, only if the price is less than 1.00

{
    TableName: "Music",
    KeyConditionExpression: "Artist = :a",
    FilterExpression: "Price < :p",
    ExpressionAttributeValues: {
        ":a": "No One You Know",
        ":p": 1.00
    }
}
```

**참고**  
`FilterExpression`은 `Query`가 일치하는 항목을 읽은 후 적용되므로 소비되는 읽기 용량을 줄이지 않습니다. 가능한 경우 범위 조건이 효율적인 쿼리를 위해 정렬 키에 `KeyConditionExpression`을 사용하도록 데이터를 모델링합니다. 자세한 내용은 [DynamoDB에서 테이블 쿼리](Query.md) 섹션을 참조하세요.

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

PartiQL에서는 `ExecuteStatement` 작업과 파티션 키에 `Select` 문을 사용하여 쿼리를 수행할 수 있습니다.

```
SELECT AlbumTitle, Year, Price
FROM Music
WHERE Artist='No One You Know'
```

이와 같이 `SELECT` 문을 사용하면 이 특정 `Artist`와 연결된 모든 곡이 반환됩니다.

`Select` 및 `ExecuteStatement`를 사용하는 코드 예제는 [DynamoDB의 PartiQL select 문](ql-reference.select.md) 섹션을 참조하세요.

------

# 테이블 스캔 비교
<a name="SQLtoNoSQL.ReadData.Scan"></a>

SQL에서 `SELECT` 절이 없는 `WHERE` 문은 테이블의 모든 행을 반환합니다. Amazon DynamoDB에서 `Scan` 작업도 동일한 작업을 수행합니다. 두 경우 모두 모든 항목 또는 일부 항목만 검색할 수 있습니다.

SQL 데이터베이스를 사용하건 NoSQL 데이터베이스를 사용하건 스캔은 시스템 리소스를 많이 사용할 수 있으므로 꼭 필요할 때만 사용해야 합니다. 스캔이 적절하거나(작은 테이블을 스캔할 때) 불가피한(데이터를 대량으로 내보낼 때) 경우도 있습니다. 하지만 일반적으로는 스캔 수행을 피할 수 있도록 애플리케이션을 설계해야 합니다. 자세한 내용은 [DynamoDB에서 테이블 쿼리](Query.md) 섹션을 참조하세요.

**참고**  
대량 내보내기를 수행하면 파티션당 하나 이상의 파일이 만들어집니다. 각 파일의 모든 항목은 해당 파티션의 해시된 키스페이스에서 가져온 것입니다.

**Topics**
+ [SQL에서 테이블 스캔](#SQLtoNoSQL.ReadData.Scan.SQL)
+ [DynamoDB에서 테이블 스캔](#SQLtoNoSQL.ReadData.Scan.DynamoDB)

## SQL에서 테이블 스캔
<a name="SQLtoNoSQL.ReadData.Scan.SQL"></a>

SQL에서는 `WHERE` 절을 지정하지 않고 `SELECT` 문을 사용하여 테이블을 스캔하고 모든 데이터를 가져올 수 있습니다. 결과에 하나 이상의 열이 포함되도록 요청할 수 있습니다. 또는 와일드카드 문자(\$1)를 사용하는 경우 모든 열을 요청할 수 있습니다.

다음은 `SELECT` 문 사용의 예입니다.

```
/* Return all of the data in the table */
SELECT * FROM Music;
```

```
/* Return all of the values for Artist and Title */
SELECT Artist, Title FROM Music;
```

## DynamoDB에서 테이블 스캔
<a name="SQLtoNoSQL.ReadData.Scan.DynamoDB"></a>

Amazon DynamoDB에서는 DynamoDB API나 SQL [PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html)(호환 쿼리 언어)을 사용하여 테이블에서 스캔을 수행할 수 있습니다.

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

DynamoDB API에서는 `Scan` 작업을 통해 테이블 또는 보조 인덱스의 모든 항목에 액세스하여 하나 이상의 항목 및 항목 속성을 반환합니다.

```
// Return all of the data in the table
{
    TableName:  "Music"
}
```

```
// Return all of the values for Artist and Title
{
    TableName:  "Music",
    ProjectionExpression: "Artist, Title"
}
```

`Scan` 작업도 결과에 표시되기를 원치 않는 항목을 삭제하는 데 사용할 수 있는 `FilterExpression` 파라미터를 제공합니다. `FilterExpression`은 스캔이 수행된 후 결과가 반환되기 전에 적용됩니다. (큰 테이블에는 사용하지 않는 것이 좋습니다. 일치하는 소수의 항목이 반환되더라도 여전히 전체 `Scan`에 대한 요금이 청구됩니다.)

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

PartiQL에서는 `ExecuteStatement` 작업을 통해 `Select` 문을 사용하여 테이블의 모든 내용을 반환하여 스캔을 수행합니다.

```
SELECT AlbumTitle, Year, Price
FROM Music
```

이 문은 Music 테이블에서 모든 항목을 반환합니다.

`Select` 및 `ExecuteStatement`를 사용하는 코드 예제는 [DynamoDB의 PartiQL select 문](ql-reference.select.md) 섹션을 참조하세요.

------

# 인덱스 관리 시 관계형(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는 다음과 같이 두 종류의 인덱스를 지원합니다.
+ 글로벌 보조 인덱스 - 이 인덱스의 기본 키는 해당 테이블의 두 가지 속성 중 어느 것이나 될 수 있습니다.
+ 로컬 보조 인덱스 - 이 인덱스의 파티션 키는 해당 테이블의 파티션 키와 동일해야 합니다. 하지만 정렬 키는 다른 속성이어도 됩니다.

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)` - 이 인덱스에 필요한 초당 읽기 및 쓰기 수. (이것은 테이블의 할당 처리량 설정과 별개입니다.) 

이 작업에는 테이블의 데이터를 새 인덱스에 채우기가 포함됩니다. 채우기 중에 테이블은 사용 가능한 상태를 유지합니다. 하지만 인덱스의 `Backfilling` 속성이 true에서 false로 바뀔 때까지는 인덱스를 사용할 수 없습니다. `DescribeTable` 작업을 사용하여 이 속성을 볼 수 있습니다.

## 인덱스를 쿼리하고 스캔할 때 관계형(SQL) 데이터베이스와 DynamoDB 비교
<a name="SQLtoNoSQL.Indexes.QueryAndScan"></a>

Amazon DynamoDB의 `Query` 및 `Scan` 작업과 SQL의 SELECT 문을 사용한 인덱스 쿼리 및 스캔을 비교합니다.

**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*에 대한 몇 가지 쿼리입니다. (이 인덱스의 키 스키마는 *Genre*와 *Price*로 구성됩니다.)

------
#### [ 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에서는 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) 섹션을 참조하세요.

------

# 테이블에서 데이터를 수정할 때 관계형(SQL) 데이터베이스와 DynamoDB 비교
<a name="SQLtoNoSQL.UpdateData"></a>

SQL 언어는 데이터 수정을 위한 `UPDATE` 문을 제공합니다. Amazon DynamoDB는 비슷한 태스크를 위해 `UpdateItem` 작업을 사용합니다.

**Topics**
+ [SQL에서 테이블의 데이터 수정](#SQLtoNoSQL.UpdateData.SQL)
+ [DynamoDB에서 테이블의 데이터 수정](#SQLtoNoSQL.UpdateData.DynamoDB)

## SQL에서 테이블의 데이터 수정
<a name="SQLtoNoSQL.UpdateData.SQL"></a>

SQL에서는 `UPDATE` 문을 사용하여 하나 이상의 행을 수정합니다. `SET` 절은 하나 이상의 열의 새로운 값을 지정하고, `WHERE` 절은 어떤 행이 수정되는지 결정합니다. 다음은 예입니다.

```
UPDATE Music
SET RecordLabel = 'Global Records'
WHERE Artist = 'No One You Know' AND SongTitle = 'Call Me Today';
```

`WHERE` 절과 일치하는 행이 없으면 `UPDATE` 문은 영향을 미치지 않습니다.

## DynamoDB에서 테이블의 데이터 수정
<a name="SQLtoNoSQL.UpdateData.DynamoDB"></a>

DynamoDB에서는 클래식 API나 [PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html)(SQL 호환 쿼리 언어)을 사용하여 단일 항목을 수정할 수 있습니다. 복수의 항목을 수정하려면 복수의 작업을 사용해야 합니다.

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

DynamoDB API에서는 `UpdateItem` 작업을 사용하여 단일 항목을 수정합니다.

```
{
    TableName: "Music",
    Key: {
        "Artist":"No One You Know",
        "SongTitle":"Call Me Today"
    },
    UpdateExpression: "SET RecordLabel = :label",
    ExpressionAttributeValues: {
        ":label": "Global Records"
    }
}
```

수정할 항목의 `Key` 속성과 속성 값을 지정하는 `UpdateExpression`을 지정해야 합니다. `UpdateItem`은 'upsert' 작업처럼 동작합니다. 즉 항목이 테이블에 존재하면 업데이트되지만 그렇지 않으면 새 항목이 추가(삽입)됩니다.

`UpdateItem`은 *조건부 쓰기*를 지원하는데, 특정 `ConditionExpression`이 true로 평가되는 경우에 한해 작업이 성공합니다. 예를 들어, 다음 `UpdateItem` 작업은 노래의 가격이 2.00 이상이 아니면 업데이트를 수행하지 않습니다.

```
{
    TableName: "Music",
    Key: {
        "Artist":"No One You Know",
        "SongTitle":"Call Me Today"
    },
    UpdateExpression: "SET RecordLabel = :label",
    ConditionExpression: "Price >= :p",
    ExpressionAttributeValues: {
        ":label": "Global Records",
        ":p": 2.00
    }
}
```

`UpdateItem`은 *원자성 카운터* 즉, 증가하거나 감소할 수 있는 `Number` 형식의 속성도 지원합니다. 원자성 카운터는 여러 가지 면에서 SQL 데이터베이스의 시퀀스 발생기, 자격 증명 열 또는 자동 증분 필드와 유사합니다.

다음은 `UpdateItem` 작업을 통해 새 속성(*Plays*)을 초기화하여 노래가 재생된 횟수를 추적하는 예제입니다.

```
{
    TableName: "Music",
    Key: {
        "Artist":"No One You Know",
        "SongTitle":"Call Me Today"
    },
    UpdateExpression: "SET Plays = :val",
    ExpressionAttributeValues: {
        ":val": 0
    },
    ReturnValues: "UPDATED_NEW"
}
```

`ReturnValues` 파라미터는 업데이트된 속성의 새 값을 반환하는 `UPDATED_NEW`로 설정됩니다. 이 경우에는 0을 반환합니다.

누군가가 이 노래를 재생할 때마다 다음 `UpdateItem` 작업을 사용하여 *Plays*를 1씩 증가시킬 수 있습니다.

```
{
    TableName: "Music",
    Key: {
        "Artist":"No One You Know",
        "SongTitle":"Call Me Today"
    },
    UpdateExpression: "SET Plays = Plays + :incr",
    ExpressionAttributeValues: {
        ":incr": 1
    },
    ReturnValues: "UPDATED_NEW"
}
```

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

PartiQL에서는 PartiQL `Update` 문을 사용하여 `ExecuteStatement` 작업을 통해 테이블의 항목을 수정합니다.

이 테이블의 기본 키는 *Artist* 및 *SongTitle*로 구성됩니다. 이 속성들의 값을 지정해야 합니다.

```
UPDATE Music
SET RecordLabel ='Global Records'
WHERE Artist='No One You Know' AND SongTitle='Call Me Today'
```

다음 예와 같이 여러 필드를 한 번에 수정할 수도 있습니다.

```
UPDATE Music
SET RecordLabel = 'Global Records'
SET AwardsWon = 10
WHERE Artist ='No One You Know' AND SongTitle='Call Me Today'
```

`Update`은 *원자성 카운터* 즉, 증가하거나 감소할 수 있는 `Number` 형식의 속성도 지원합니다. 원자성 카운터는 여러 가지 면에서 SQL 데이터베이스의 시퀀스 발생기, 자격 증명 열 또는 자동 증분 필드와 유사합니다.

다음은 `Update` 문을 통해 새 속성(*Plays*)을 초기화하여 노래가 재생된 횟수를 추적하는 예제입니다.

```
UPDATE Music
SET Plays = 0
WHERE Artist='No One You Know' AND SongTitle='Call Me Today'
```

누군가가 이 노래를 재생할 때마다 다음 `Update` 문을 사용하여 *Plays*를 1씩 증가시킬 수 있습니다.

```
UPDATE Music
SET Plays = Plays + 1
WHERE Artist='No One You Know' AND SongTitle='Call Me Today'
```

**참고**  
`Update` 및 `ExecuteStatement`를 사용하는 코드 예제는 [DynamoDB의 PartiQL update 문](ql-reference.update.md) 섹션을 참조하세요.

------

# 테이블에서 데이터를 삭제할 때 관계형(SQL) 데이터베이스와 DynamoDB 비교
<a name="SQLtoNoSQL.DeleteData"></a>

SQL에서 `DELETE` 문은 테이블에서 하나 이상의 행을 제거합니다. Amazon DynamoDB에서는 `DeleteItem` 작업을 사용하여 항목을 한 번에 하나씩 삭제합니다.

**Topics**
+ [SQL에서 테이블의 데이터 삭제](#SQLtoNoSQL.DeleteData.SQL)
+ [DynamoDB에서 테이블의 데이터 삭제](#SQLtoNoSQL.DeleteData.DynamoDB)

## SQL에서 테이블의 데이터 삭제
<a name="SQLtoNoSQL.DeleteData.SQL"></a>

SQL에서는 `DELETE` 문을 사용하여 하나 이상의 행을 삭제합니다. `WHERE` 절은 수정하려는 행을 결정합니다. 다음은 예입니다.

```
DELETE FROM Music
WHERE Artist = 'The Acme Band' AND SongTitle = 'Look Out, World';
```

여러 열을 삭제하도록 `WHERE` 절을 수정할 수 있습니다. 예를 들어, 다음 예제와 같이 특정 아티스트의 모든 노래를 삭제할 수 있습니다.

```
DELETE FROM Music WHERE Artist = 'The Acme Band'
```

## DynamoDB에서 테이블의 데이터 삭제
<a name="SQLtoNoSQL.DeleteData.DynamoDB"></a>

DynamoDB에서는 클래식 API나 [PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html)(SQL 호환 쿼리 언어)을 사용하여 단일 항목을 삭제할 수 있습니다. 복수의 항목을 수정하려면 복수의 작업을 사용해야 합니다.

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

DynamoDB API에서는 `DeleteItem` 작업을 사용하여 테이블에서 데이터를 한 번에 한 항목씩 삭제합니다. 항목의 기본 키 값을 지정해야 합니다.

```
{
    TableName: "Music",
    Key: {
        Artist: "The Acme Band",
        SongTitle: "Look Out, World"
    }
}
```

**참고**  
Amazon DynamoDB는 `DeleteItem` 외에도 여러 항목을 동시에 삭제하는 `BatchWriteItem` 작업을 지원합니다.

`DeleteItem`은 *조건부 쓰기*를 지원하는데, 특정 `ConditionExpression`이 true로 평가되는 경우에 한해 작업이 성공합니다. 예를 들어, 다음 `DeleteItem` 작업은 *RecordLabel* 속성이 있는 항목만 삭제합니다.

```
{
    TableName: "Music",
    Key: {
        Artist: "The Acme Band",
        SongTitle: "Look Out, World"
    },
   ConditionExpression: "attribute_exists(RecordLabel)"
}
```

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

PartiQL에서는 `ExecuteStatement` 작업을 통해 `Delete` 문을 사용하여 테이블에서 데이터를 한 번에 한 항목씩 삭제합니다. 항목의 기본 키 값을 지정해야 합니다.

이 테이블의 기본 키는 *Artist* 및 *SongTitle*로 구성됩니다. 이 속성들의 값을 지정해야 합니다.

```
DELETE FROM Music
WHERE Artist = 'Acme Band' AND SongTitle = 'PartiQL Rocks'
```

작업에 대한 추가 조건을 지정할 수 있습니다. 다음 `DELETE` 작업은 *Awards*가 11 이상인 경우에만 항목을 삭제합니다.

```
DELETE FROM Music
WHERE Artist = 'Acme Band' AND SongTitle = 'PartiQL Rocks' AND Awards > 11
```

**참고**  
`DELETE` 및 `ExecuteStatement`를 사용하는 코드 예제는 [DynamoDB의 PartiQL delete 문](ql-reference.delete.md) 섹션을 참조하세요.

------

# 테이블 제거 시 관계형(SQL) 데이터베이스와 DynamoDB 비교
<a name="SQLtoNoSQL.RemoveTable"></a>

SQL에서는 `DROP TABLE` 문을 사용하여 테이블을 제거합니다. Amazon DynamoDB에서는 `DeleteTable` 작업을 사용합니다.

**Topics**
+ [SQL에서 테이블 제거](#SQLtoNoSQL.RemoveTable.SQL)
+ [DynamoDB에서 테이블 제거](#SQLtoNoSQL.RemoveTable.DynamoDB)

## SQL에서 테이블 제거
<a name="SQLtoNoSQL.RemoveTable.SQL"></a>

테이블이 더 이상 필요하지 않아 영구적으로 삭제하려는 경우 SQL에서 `DROP TABLE` 문을 사용합니다.

```
DROP TABLE Music;
```

테이블이 삭제되고 나면 복구할 수 없습니다. (일부 관계형 데이터베이스에서 `DROP TABLE` 작업 실행을 취소할 수는 있지만 일부 공급업체에 한정된 기능으로 널리 구현되지는 않습니다.)

## DynamoDB에서 테이블 제거
<a name="SQLtoNoSQL.RemoveTable.DynamoDB"></a>

DynamoDB에는 이와 비슷한 `DeleteTable` 작업이 있습니다. 다음 예에서는 테이블이 영구적으로 삭제됩니다.

```
{
    TableName: "Music"
}
```