일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- Route53
- 스프링테스트
- awscli
- MockMvc
- Spring
- secondaryindex
- 로드밸런서
- annotation
- filterexpression
- 오류
- AWS
- javaspring
- Springsecurity
- EmbeddedId
- partiql
- 자바
- query
- compositekey
- 자바스프링
- awscloud
- 스프링
- markerinterface
- 개발
- 테스트코드
- 도메인
- DynamoDB
- Java
- IdClass
- 다이나모디비
- testresttemplate
- Today
- Total
아장아장 개발 일기
DynamoDB API와 PartiSQL 본문
PartiQL 이란?
- SQL 호환 쿼리 언어
- DynamoDB에서 PartiQL이 지원되기 전에는 DynamoDB API를 사용해야만 데이터를 읽거나 쓰기가 가능했다.
- PartiQL이 지원되면서 RDBMS에서 SQL을 사용하는 것과 같이 데이터를 다를 수 있게 되었다.
DynamoDB에서 데이터 읽기
- DynamoDB.DocumentClient의 get, query, scan, batchGet 등의 API를 사용하여 데이터를 읽을 수 있다.
- scan : 테이블 내의 모든 아이템을 가져옴 (→ 모든 아이템을 조회한 요금으로 청구되기 때문에 유의해야함)
- query : 테이블 생성시 설정하는 파티션키를 기준으로 아이템을 검색
(기존 API를 사용할 경우)
import aws from "aws-sdk";
const docClient = new aws.DynamoDB.DocumentClient();
const params = {
TableName: "MisoTable",
Key: {
id: 1,
},
};
docClient.get(params, (err, data) => {
// handle data.Item and errors
});
(PartiQL을 사용할 경우)
import aws from "aws-sdk";
const dynamoDb = new aws.DynamoDB();
const statement = `SELECT * FROM "MisoTable" where id = 1`;
const result = await dynamoDb
.executeStatement({
Statement: statement,
})
.promise();
// handle result.Items
⇒ 위의 API 호출 코드와 아래의 PartiQL 코드는 같은 아이템을 가져오지만, 결과값의 형태가 다르다.
기존 API의 get 메서드를 사용하면 코드에서 바로 사용할 수 있는 객체가 반환되고,
PartiQL의 executeStatement 메서드를 사용하면 DynamoDB.AttributeMap의 리스트가 반환된다.
(후자의 경우 executeStatement로 받은 결과를 aws-sdk에서 지원해주는 Converter의 unmarshall 메서드를 사용하여 변환)
Query API
- KeyConditionExpression : 필수조건인 파티션키의 연산조건은 ‘=’로 한정된다.
- KeyConditionExpression은 = 연산자만 지원하기 때문에 아래 소스는 오류를 발생시킨다.
const wrongParams = {
TableName: "UserTable",
KeyConditionExpression: "id > :id",
ExpressionAttributeValues: {
":id": 1,
} as DynamoDB.ExpressionAttributeValueMap,
ProjectionExpression: "id",
};
KeyConditionExpression은 필수값이기 때문에 해당 값이 없는 아래 소스는 오류를 발생시킨다.
(scan method를 사용해서 실행시켜야함)
const rightParams = {
TableName: "UserTable",
FilterExpression: "id > :id",
ExpressionAttributeValues: {
":id": 1,
} as DynamoDB.ExpressionAttributeValueMap,
ProjectionExpression: "id",
};
FilterExpression의 경우 =, <, ≤, >, ≥, BETWEEN, IN 과 같이 다양한 연산을 지원한다.
PartiQL
- KeyCondition, FilterExpression의 구분이 없다.
- 편리하지만, 주의하지 않을경우 query조건이 아닌, scan 조건이 되버려 테이블의 모든 아이템을 검색하도록 동작할 수 있다.
- 다음과 같은 select 문은 테이블 전체를 scan 한다.
const statement = `SELECT id FROM "UserTable" where id > 1`;
- where 조건절에서 파티션 키의 연산조건은 =과 IN으로 한정되기 때문이다.
- PartiQL 파티션키 연산조건 중 IN을 코드로 구현하려면 batchGet을 사용해야한다.
const params = {
RequestItems: {
["UserTable"]: {
Keys: [{ id: 1 }, { id: 2 }],
ProjectionExpression: "booking_id, due_date_duration",
},
},
} as DynamoDB.DocumentClient.BatchGetItemInput;
docClient.batchGet(params, (err, data) => {
// handle data and errors
});
query의 KeyConditionExpression에서는 한번의 하나의 파티션 키만 허용한다.
(→ 아래 소스 오류 발생)
const params = {
TableName: "UserTable",
KeyConditionExpression: "id IN (:id1, :id2)",
ExpressionAttributeValues: {
":id1": 1,
":id2": 2,
} as DynamoDB.ExpressionAttributeValueMap,
ProjectionExpression: "id",
};
userTable의 파티션키는 id이며 정렬키(sort key)는 별도로 설정하지 않는다.
만약 파티션키와 정렬키가 모두 설정되어있으면 위의 코드들은 동일한 결과를 주지 않는다.
만약 파티션키와 정렬키가 UserTable에 모두 설정되어있다면 위의 PartiQL의 IN조건 코드는 정상동작하지만 batchGet 코드는 정렬키가 없기 때문에 동작하지 않는다.
⇒ 즉 위 두 코드는 완전히 동등한 형태의 변환은 아님
PartiQL과 limit키워드
- PartiQL에서는 limit이라는 키워드가 작동하지 않는다.
// 아래 코드는 오류를 발생시킴
const statement = `SELECT id FROM "CustomerDeviceTable" where os_type = 'ios' and customer_id > 1 limit 5`;
- PartiQL에서 limit을 설정하려면 DynamoDB.Types.ExecuteStatementInput에서 limit을 설정해줘야한다.
const statement = `SELECT id FROM "CustomerDeviceTable" where os_type = 'ios' and customer_id > 1`;
const result = await dynamoDb
.executeStatement({
Statement: statement,
Limit: 5,
})
.promise();
PartiQL에서 limit의 동작 방식
Query API를 사용할 경우의 limit 동작방식
- 아래는 PartiQL에서 limit동작하는 방식을 보기 위핸 예제 테이블인 CustomerDeviceTable 이다.
os_type (partition key) | customer_id (sort key) | created_at |
ios | 1 | 2022-07-10T07:00:00.000Z |
ios | 2 | 2022-07-11T07:00:00.000Z |
ios | 3 | 2022-07-12T07:00:00.000Z |
ios | 4 | 2022-07-13T07:00:00.000Z |
ios | 5 | 2022-07-14T07:00:00.000Z |
android | 6 | 2022-07-15T07:00:00.000Z |
- 위의 테이블에서 기종이 ios이고 7월 10일 혹은 7월 13일에 생성된 아이템을 불러오고싶다면 아래와 같은 코드를 쓸 수 있다.
const params = {
TableName: "CustomerDeviceTable",
KeyConditionExpression: "os_type = :os_type",
FilterExpression: "created_at in (:created_at1, :created_at2)",
ExpressionAttributeValues: {
":os_type": "ios",
":created_at1": "2022-07-10T07:00:00.000Z",
":created_at2": "2022-07-13T07:00:00.000Z",
} as DynamoDB.ExpressionAttributeValueMap,
ProjectionExpression: "os_type, customer_id, created_at",
ScanIndexForward: true,
Limit: 3,
};
- 위의 코드에 대한 결과값으로 아래를 기대한다
[
{
"os_type": "ios",
"customer_id": 1,
"created_at": "2022-07-10T07:00:00.000Z"
},
{
"os_type": "ios",
"customer_id": 4,
"created_at": "2022-07-13T07:00:00.000Z"
}
]
- 하지만 실제로 반환되는 아이템은 아래 한가지이다.
{
"os_type": "ios",
"customer_id": 1,
"created_at": "2022-07-10T07:00:00.000Z"
}
⇒ 이는 filter의 동작이 Limit 보다 나중에 처리되기 때문이다.
즉, limit 설정에 의해 customer_id 1~3까지 가져온 후 그 안에서 filter가 적용돼 customer_id가 1인 아이템만 반환된다.
filter는 DynamoDB의 읽기(read) 사용 요금을 줄여주지 못하기 때문에 위와 같은 쿼리를 만들때는 주의가 필요하다.
PartiQL에서의 limit 동작 방식
const statement = `SELECT id FROM "CustomerDeviceTable" where os_type = 'ios' and created_at in ('2022-07-10T07:00:00.000Z', '2022-07-13T07:00:00.000Z') order by customer_id asc`;
const result = await dynamoDb
.executeStatement({
Statement: statement,
Limit: 3,
})
.promise();
위의 코드 역시 API 호출과 동일하게 한개의 아이템을 반환한다.
⇒ 즉 API나 PartiQL이나 limi과 filter가 동일하게 동작한다.
그럼 어떤걸 써야하나?
API와 PartiQL 둘의 성능상 차이가 없으니 선호하는 방법으로 코드를 작성해도 무관하다.
다만 PartiQL의 경우 where절에 key조건과 filter 조건을 섞어 사용할 수 있기 때문에 API보다 좀 더 주의를 기울여야한다.
참고 자료
'개발 > AWS' 카테고리의 다른 글
DynamoDB 기본기 (PrimaryKey, SecondaryIndex, FilterExpression (0) | 2023.03.10 |
---|---|
HTTP → HTTPS Redirect(AWS Cloud) (0) | 2022.11.30 |
AWS 클라우드 활용, 도메인에 SSL 적용하기 A to Z(Route53, Certificate Manager, Load Balancer) (0) | 2022.08.01 |
AWS Route53에서 도메인 연결 및 Host zone 관리 방법 (0) | 2022.07.29 |
Spring + AWS Cognito 세팅 및 로그인, 회원가입, 로그아웃 구현 (0) | 2022.06.15 |