Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

DynamoDB keys: query or scan

After this lesson: I can say why a query is cheaper than a scan.

55 min lessonNo commands

Does a shop read every order?

A DynamoDB query reads the items under one key, while a scan reads the whole table. The difference decides how fast and how cheap every read in your app will be.

An online shop holds a million orders. One customer asks to see hers. A query goes straight to her orders and reads nothing else. The counts the service sends back show the work it did.

By the end of this lesson

Note

I can say why a query is cheaper than a scan.

Key words

WordWhat it means
Partition keythe attribute that decides where an item is stored
Sort keythe attribute that puts items in order inside one partition key
Key conditionthe test a query makes on the keys
Querya read that goes to one partition key
Scana read that looks at every item in the table
Filtera test applied after the items are read

The cells students fill in are left blank in this preview.

Two keys give every item an address

Our orders table has two key attributes. The partition key is customer. It decides where the service stores an item, so all of one customer's orders sit together.

The sort key is order_id. It puts the orders of one customer in order. Together the two keys name exactly one item. Two orders may share a customer, but never both keys.

Worked example: how the orders are laid out

Partition key: customerSort key: order_idOther attributes
ana1tea, paid, total 4
ana2milk, new, total 2
ana3cake, paid, total 15
ben7tea, paid, total 8
cai4milk, new, total 6
cai9tea, paid, total 3

The cells students fill in are left blank in this preview.

Query goes to one place, scan everywhere

A query names the partition key. It must, or the service refuses with a ValidationException and HTTP status 400. The service goes straight to that customer and reads only those orders.

A scan names nothing. It reads every item in the table, one after another. Both answers carry a Count, the items returned, and a ScannedCount, the items looked at.

Try it: a query and a scan

Code: python
orders = [
    {"customer": {"S": "ana"}, "order_id": {"N": "1"}, "status": {"S": "paid"}},
    {"customer": {"S": "ana"}, "order_id": {"N": "2"}, "status": {"S": "new"}},
    {"customer": {"S": "ana"}, "order_id": {"N": "3"}, "status": {"S": "paid"}},
    {"customer": {"S": "ben"}, "order_id": {"N": "7"}, "status": {"S": "paid"}},
    {"customer": {"S": "cai"}, "order_id": {"N": "4"}, "status": {"S": "new"}},
    {"customer": {"S": "cai"}, "order_id": {"N": "9"}, "status": {"S": "paid"}},
]

def scan(items):
    return {"Count": len(items), "ScannedCount": len(items)}

def query(items, customer):
    found = []
    for item in items:
        if item["customer"]["S"] == customer:
            found.append(item)
    return {"Count": len(found), "ScannedCount": len(found)}

print("scan:", scan(orders))
print("query ana:", query(orders, "ana"))
# Change "ana" to "ben". How many items does the query look at now?

A filter trims the answer, not the work

A key condition can also test the sort key. For example, order_id of 2 or more. The service then reads only that part of the partition.

A filter tests any other attribute, such as status. It runs after the items are read, so it changes the Count but not the ScannedCount.

Worked example: ana's paid orders from 2

StepItems leftWhat happened
Partition key is ana3orders 1, 2 and 3
Sort key 2 or more2orders 2 and 3, so ScannedCount is 2
Filter: status is paid1order 3 only, so Count is 1

The cells students fill in are left blank in this preview.

A common mistake

Warning

Many people think a filter makes a read cheaper. It does not. The service reads the items first and drops some afterwards. Put what you can into the key condition, and use a filter only for what is left.

Try it: read the two counts

Code: python
answer = {
    "Count": 1,
    "ScannedCount": 2,
    "Items": [
        {"customer": {"S": "ana"}, "order_id": {"N": "3"}, "status": {"S": "paid"}},
    ],
}

dropped = answer["ScannedCount"] - answer["Count"]
print("looked at:", answer["ScannedCount"])
print("returned:", answer["Count"])
print("dropped by the filter:", dropped)
# Change ScannedCount to 3. What does it say the filter dropped?

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.