NoSQL (DynamoDB)

Part 4. ๋ฐ์ดํ„ฐ์˜ ์ดํ•ด์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

๋ณธ ํฌ์ŠคํŒ…์€ ํŒจ์ŠคํŠธ์บ ํผ์Šค(FastCampus)์˜ ๋ฐ์ดํ„ฐ ์—”์ง€๋‹ˆ์–ด๋ง ์˜ฌ์ธ์› ํŒจํ‚ค์ง€ Online์„ ์ฐธ๊ณ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์ด ํฌ์ŠคํŒ…์€ NoSQL ์ค‘ DynamoDB๋ฅผ ์œ„์ฃผ๋กœ ์„œ์ˆ ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

1. NoSQL vs. RDB

  • Not Only SQL
  • ์ฐจ์ด์ (1) ๋‹ค์ด๋‚˜๋ฏน ์Šคํ‚ค๋งˆ
    • ๊ตฌ์กฐ๋ฅผ ์ •์˜ํ•˜์ง€ ์•Š๊ณ ๋„ Documents, Key Values ๋“ฑ์„ ์ƒ์„ฑ
    • ๊ฐ๊ฐ์˜ Document๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ๊ตฌ์กฐ๋กœ ๊ตฌ์„ฑ ๊ฐ€๋Šฅ
    • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋“ค๋งˆ๋‹ค ๋‹ค๋ฅธ syntax
    • ํ•„๋“œ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ
  • ์ฐจ์ด์ (2) Scalabilty
    • SQL DB: vertically scalable - CPU, RAM, SSD๋กœ ์šฉ๋Ÿ‰ ๋ฌธ์ œ ํ•ด๊ฒฐ๊ฒฐ
    • NoSQL DB: horizontally scalable - Sharding, Partitioning๋กœ ์šฉ๋Ÿ‰ ๋ฌธ์ œ ํ•ด๊ฒฐ

2. Partition

  • ๋ฐ์ดํ„ฐ ๋‚˜๋ˆ„๊ธฐ(vertical & horizontal)
    • ๋ฐ์ดํ„ฐ ๋งค๋‹ˆ์ง€๋จผํŠธ, ํผํฌ๋จผ์Šค ๋“ฑ ๋‹ค์–‘ํ•œ ์ด์œ 
  1. Vertical Partition
    • ํ…Œ์ด๋ธ”์„ ๋” ์ž‘์€ ํ…Œ์ด๋ธ”๋กœ ๋‚˜๋ˆ„๊ธฐ(Normalization์™€๋Š” ๋‹ค๋ฆ„)
    • ex. ์ง€์†์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ๋˜๋Š” ์นผ๋Ÿผ๊ณผ ์•„๋‹Œ ์นผ๋Ÿผ๋“ค ๋‚˜๋ˆ„๊ธฐ
  2. Horizontal Partition
    • Schema / Structure ์ž์ฒด๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์ž์ฒด๋ฅผ Sharded Key๋กœ ๋ถ„๋ฆฌ
    • NosQL DB์—์„œ๋Š” ํ•„์ˆ˜์ ์ด๋‹ค.

3. DynamoDB

  • aws.amazon.com > DynamoDB
  • Partition Key๋Š” SQL์—์„œ Primary Key์™€ ์œ ์‚ฌํ•˜๋‹ค.

4. AWS SDK - Boto3 Package (DynamoDB ์—ฐ๊ฒฐ)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import sys
import os
import boto3
import logging

def main():
    try:
        dynamodb = boto3.resource('dynamodb', region_name='ap-northeast-2', endpoint_url='http://dynamodb.ap-northeast-2.amazonaws.com')
    except:
        logging.error("could not connect to dynamodb")
        sys.exit(1)

    print('Success')

if __name__=='__main__':
    main()

5. ํ…Œ์ด๋ธ” ์ƒ์„ฑ ๋ฐ ์ŠคํŽ™

  • Provisioned(ํ• ๋‹น๋จ) vs. On-demand(์˜จ๋””๋งจ๋“œ)

6. Global Index, Local Index

7. INSERT(Single, Batch items)

boto3 Documentation ์ฝ์–ด๋ณด๊ธฐ

Creating a New Item
1
2
3
4
5
6
7
8
9
table.put_item(
   Item={
        'username': 'janedoe',
        'first_name': 'Jane',
        'last_name': 'Doe',
        'age': 25,
        'account_type': 'standard_user',
    }
)
Batch Writing
 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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
with table.batch_writer() as batch:
    batch.put_item(
        Item={
            'account_type': 'standard_user',
            'username': 'johndoe',
            'first_name': 'John',
            'last_name': 'Doe',
            'age': 25,
            'address': {
                'road': '1 Jefferson Street',
                'city': 'Los Angeles',
                'state': 'CA',
                'zipcode': 90001
            }
        }
    )
    batch.put_item(
        Item={
            'account_type': 'super_user',
            'username': 'janedoering',
            'first_name': 'Jane',
            'last_name': 'Doering',
            'age': 40,
            'address': {
                'road': '2 Washington Avenue',
                'city': 'Seattle',
                'state': 'WA',
                'zipcode': 98109
            }
        }
    )
    batch.put_item(
        Item={
            'account_type': 'standard_user',
            'username': 'bobsmith',
            'first_name': 'Bob',
            'last_name':  'Smith',
            'age': 18,
            'address': {
                'road': '3 Madison Lane',
                'city': 'Louisville',
                'state': 'KY',
                'zipcode': 40213
            }
        }
    )
    batch.put_item(
        Item={
            'account_type': 'super_user',
            'username': 'alicedoe',
            'first_name': 'Alice',
            'last_name': 'Doe',
            'age': 27,
            'address': {
                'road': '1 Jefferson Street',
                'city': 'Los Angeles',
                'state': 'CA',
                'zipcode': 90001
            }
        }
    )

8. ๋ฐ์ดํ„ฐ ์š”์ฒญ ๋ฐ ์ œํ•œ์ 

boto3 Documentation ์ฝ์–ด๋ณด๊ธฐ

Getting an Item
1
2
3
4
5
6
response = table.get_item(
    Key = {
        'artist_id': '00FQb4jTyendYWaN8pK0wa',
        'id': '0Oqc0kKFsQ6MhFOLBNZIGX'
    }
)
ClientError: An error occurred (ValidationException) when calling the GetItem operation: The provided key element does not match the schema

์œ„์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋œฌ๋‹ค๋ฉด, key๊ฐ’์„ ์ œ๋Œ€๋กœ ๋‹ค ๋„ฃ์—ˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณธ๋‹ค.

Querying and Scanning
  • Querying: Primary Key ๊ฐ’์„ ์•Œ๊ณ  ์žˆ์„ ๋•Œ ํ™œ์šฉ
  • Scanning: Primary Key ๊ฐ’์„ ๋ชจ๋ฅด์ง€๋งŒ, ๋‹ค๋ฅธ attribute๋ฅผ ์•Œ ๋•Œ ํ™œ์šฉ
    - Scan์€ ๋ชจ๋“  ํ–‰์„ ๋‹ค ํ›‘๋Š” ๋น„ํšจ์œจ์ ์ธ ๊ธฐ๋Šฅ์ด๋ฏ€๋กœ ๊ผญ ํ•„์š”ํ•  ๋•Œ๋งŒ ์“ฐ๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋œ๋‹ค.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Querying
response = table.query(
    KeyConditionExpression=Key('artist_id').eq('00FQb4jTyendYWaN8pK0wa'),
    FilterExpression=Attr('popularity').gt(75) #query๋„ filterexpresson ์“ธ ์ˆ˜ ์žˆ๋‹ค!
)
print(len(response['Items']))

# Scanning
response = table.scan(
    FilterExpression=Attr('popularity').gt(75)
)
print(len(response['Items']))