Roland Ettinger
Roland Ettinger

Reputation: 2855

DynamoDBMapper load vs query

The DynamoDBMapper provides different ways to read one item from a table:

Is there a recommendation, which of them to use? In a quick test, the following two code snippets return the same "MyEntry" item for a table with primary key=hash and range key=date, whereas the query method is roughly 10% faster.

load

public MyEntry getEntryForDay(final Integer hash, final LocalDate date) {
    return mapper.load(MyEntry.class, hash, date);
}

query

public MyEntry getEntryForDay(final Integer hash, final LocalDate date) {
    final MyEntry hashKeyValues = new MyEntry ();
    hashKeyValues.setHash(hash);
    final Condition rangeKeyCondition = new Condition()//
            .withComparisonOperator(ComparisonOperator.EQ.toString())//
            .withAttributeValueList(new AttributeValue().withS(new LocalDateMarshaller().marshall(date)));
    final DynamoDBQueryExpression<MyEntry> queryExpression = new DynamoDBQueryExpression<MyEntry>()//
            .withHashKeyValues(hashKeyValues)//
            .withRangeKeyCondition("date", rangeKeyCondition)//
            .withLimit(1);
    final List<MyEntry> storedEntries = mapper
            .query(MyEntry.class, queryExpression);
    if (storedEntries.size() == 0) {
        return null;
    }
    return storedEntries.get(0);
}

Upvotes: 22

Views: 29667

Answers (2)

Roland Ettinger
Roland Ettinger

Reputation: 2855

Ok, now as I'm getting more used to work with DynamoDB it turns out that a bug in the mapper.query code is causing the poorer performance:

  • The "withLimit(1)" does not in fact limit the total results returned in the list but instead the results are returned in a "PaginatedQueryList" and the actual items are lazily loaded from DB if accessed. WithLimit(1) actually limits the items loaded with each request.
  • The actual bug is the part "if (storedEntries.size() == 0)", as the size() call loads in fact ALL items in the list. With the withLimit(1) this results in the poorest possible performance.

The correct code for the mapper query is:

public MyEntry getEntryForDay(final Integer hash, final LocalDate date) {
    final MyEntry hashKeyValues = new MyEntry ();
    hashKeyValues.setHash(hash);
    final Condition rangeKeyCondition = new Condition()//
            .withComparisonOperator(ComparisonOperator.EQ.toString())//
            .withAttributeValueList(new AttributeValue().withS(new LocalDateMarshaller().marshall(date)));
    final DynamoDBQueryExpression<MyEntry> queryExpression = new DynamoDBQueryExpression<MyEntry>()//
            .withHashKeyValues(hashKeyValues)//
            .withRangeKeyCondition("date", rangeKeyCondition)//
            .withLimit(1);
    final List<MyEntry> storedEntries = mapper
            .query(MyEntry.class, queryExpression);
    if (storedEntries.isEmpty()) {
        return null;
    }
    return storedEntries.get(0);
}

Upvotes: 7

Ben Schwartz
Ben Schwartz

Reputation: 1756

Load and Query are different operations:

If you have a hash key only schema, they perform the same operation - retrieve the item with the hash key specified.

If you have a hash-range schema, load retrieves a specific item identified by a single hash + range pair. Query retrieves all items that have the specified hash key and meet the range key conditions.

Since you are using the equality operator for both the hash key and range key, the operations are exactly equivalent.

Upvotes: 25

Related Questions