A cou­ple of weeks ear­lier, Ama­zon announced sup­port for Local Sec­ondary Indexes (LSI) for DynamoDB. You can now per­form fast, effi­cient queries against DynamoDB tables using attrib­utes that are not part of the exist­ing Hash and Range key model with­out resort­ing to the use of scans.

As a result to the new fea­ture the DynamoDB query API has also gone through some changes, as did the AWSSDK for .Net. From ver­sion 1.5.18.0 onwards, there’s a new top level name­space Amazon.DynamoDBv2 which con­tains a mir­ror set of types to those under the orig­i­nal Amazon.DynamoDB name­space, albeit with minor changes to sup­port the new LSI feature.

Query syn­tax change

Due to the changes in the under­ly­ing AWSSDK, I have decided to make some changes to the query syn­tax sup­ported by DynamoDB.SQL too – namely, to remove the need for the spe­cial key­words @HashKey and @RangeKey and instead allow you to use the attrib­utes names for your hash and range keys.

For exam­ple, given a table like the one out­lined in the DynamoDB docs:

image

To write a query to find all sub­jects start­ing with “a” in the “S3” forum, you would pre­vi­ously write:

SELECT * FROM Thread WHERE @HashKey = \”S3\” AND @RangeKey BEGINS WITH \”a\”

In the new ver­sion of DynamoDB.SQL, you would write the fol­low­ing instead:

SELECT * FROM Thread WHERE Forum­Name = \”S3\” AND Sub­ject BEGINS WITH \”a\”

This syn­tax change only applies to the exten­sion meth­ods for the Ama­zon­Dy­namoD­B­Client and DynamoD­B­Con­text types under the new Amazon.DynamoDBv2 name­space. The exten­sion meth­ods them­selves are only avail­able under a new name­space DynamoDbV2.SQL.Execution in the DynamoDb.SQL.dll.

The syn­tax for scans on the other hand, has remained the same in both the new and the old API.

Local Sec­ondary Index support

You can spec­ify that a query should use a Local Sec­ondary Index (LSI) by using the Index option in the WITH clause.

For exam­ple, given a Thread table and an index Last­PostIn­dex, as out­lined in the DynamoDB docs:

image

To find all the posts in the “S3” forum since the 1st May 2013, you can write the query as following:

SELECT * FROM Thread WHERE Forum­Name = \”S3\” AND Last­Post­Date­Time >= \”2013–05-01\”

WITH (Index(LastPostIndex, true))

The WITH clause is where you spec­ify optional query para­me­ters, such as NoCon­sis­ten­tRead, and Page­Size. (please refer to the Get­ting Started guide on avail­able query parameters).

The Index option allows you to spec­ify the name of the index, in this case that’s “Last­PostIn­dex”, and a boolean flag to spec­ify whether or not all attrib­utes should be returned.

For the above query, because we’re ask­ing for all attrib­utes to be sent back with *, and that attrib­utes such as Replies are not pro­jected into the index, they will be fetched (auto­mat­i­cally per­formed by DynamoDB) from the main table at addi­tional con­sumed capac­ity units.

 

On the other hand, if you want only the pro­jected attrib­utes back from the index, we can tweak the query slightly:

SELECT * FROM Thread WHERE Forum­Name = \”S3\” AND Last­Post­Date­Time >= \”2013–05-01\”

WITH (Index(LastPostIndex, false))

In which case, only Forum­Name, Last­Post­Date­Time and Sub­ject will be returned by the query.

 

Finally, if you are inter­ested in a spe­cific set of attrib­utes, you can also spec­ify them in the SELECT clause:

SELECT Forum­Name, Sub­ject FROM Thread

WHERE Forum­Name = \”S3\” AND Last­Post­Date­Time >= \“2013–05-01\”

WITH     (Index(LastPostIndex, false))

 

Some ref­er­ence links:

AWS announces Local Sec­ondary Index sup­port for DynamoDB

DynamoDB docs on Local Sec­ondary Indexes

DynamoDB docs on Query

Query­ing with an Index attribute in DynamoDB.SQL

Get­ting started with DynamoDB.SQL

Share

Just a quick note to say that another minor update to DynamoDB.SQL has been release, you can view the release notes here.

 

The lat­est update adds sup­port for a TSQL style WITH key­word for spec­i­fy­ing optional para­me­ters for tweak­ing the query/scan oper­a­tion. For queries, you can spec­ify the NoCon­sis­ten­tRead and Page­Size options to use even­tu­ally con­sis­tent read and throt­tle the num­ber of items returned per request respec­tively. Sim­i­larly for scans, you can use the Page­Size option for throt­tling your scan requests too, but the DynamoDB scans does not sup­port strong con­sis­tency.

 

Accord­ing to DynamoDB best prac­tices, you should avoid sud­den bursts of read activ­ity, using the new Page­Size option you can make sure that your query/scan does not con­sume too many read capac­ity unit in a short burst and end up caus­ing more crit­i­cal reads to be throttled.

 

For exam­ple, a query which returns 10 items per request using even­tu­ally con­sis­tent read will look some­thing like this:

image

whereas a scan will look like:

image

For more details about the full syn­tax, please refer to the Get­ting Started doc­u­ment, which has been updated to include the new WITH key­word.

 

Enjoy!

Share

Just a quick note to say that I have made some minor changes to DynamoDb.SQL and released ver­sion 1.0.7 of the library to Nuget, here’s a list of the changes:

  • fixed a bug with LIMIT when there is insuf­fi­cient num­ber of ele­ments using the DynamoD­B­Con­text.
  • added sup­port for count­ing the num­ber of match­ing items with a query or scan (see below)

image

image

The Get­ting Started guide has also been updated to include details on how to write a Count query.

Share

Just a quick note to say that I have made some minor changes to DynamoDb.SQL to:

  • Add sup­port for spec­i­fy­ing the ScanIn­dex­For­ward option(see DynamoDB API doc here for detail) in a Query oper­a­tion using an optional “ORDER” clause

image

  • Fixed a bug where when query­ing using the exten­sion meth­ods on the DynamoD­B­Con­text class, the LIMIT clause is not being respected. This was due to lazy-loading of results in the DynamoD­B­Con­text class, see this thread for more info.

 

The lat­est build can be found on Nuget as ver­sion 1.0.5.

Share

Amazon’s DynamoDB is a won­der­ful prod­uct – scal­able, durable, fast, with pre­dictable latency num­bers unlike Sim­pleDB. How­ever, the only gripe I have with DynamoDB is that there is no built-in sup­port for a query lan­guage, which makes life rather dif­fi­cult when you want to per­form a query or a scan against the data you have in DynamoDB.

Whilst the stan­dard AWS SDK for .Net pro­vides a num­ber of dif­fer­ent ways to per­form queries and scans:

  • using the low-level Ama­zon­Dy­namoD­B­Client
  • using the Table helper class
  • using the DynamoD­B­Con­text ORM

none of these ways are easy to use and the few attempts to use them in our code­base left a bad taste in my mouth and an exter­nal DSL is des­per­ately needed to make it eas­ier to express the query we’d like to per­form against data stored in DynamoDB.

Intro­duc­ing DynamoDb.SQL

It is because of these lim­i­ta­tions that I decided to add a SQL-like exter­nal DSL on top of exist­ing func­tion­al­i­ties to make it eas­ier for .Net devel­op­ers to work with DynamoDB.

Hav­ing spent a cou­ple of week­ends I have put together a sim­ple library called DynamoDb.SQL, which you can down­load and try it your­self from Nuget here. This library adds an exter­nal DSL on top of the exist­ing func­tion­al­i­ties of the .Net AWS SDK and allows you to query and scan DynamoDB using nat­ural, SQL-like syntax.

Using this syn­tax, a query can be expressed with the gen­eral format:

image

where @HashKey and @RangeKey are spe­cial key­words to mean the hash and range key in your table, and oper­a­tor can be one of the allowed com­par­i­son oper­a­tors for a query request :

=, >=, >, <=, <, BEGINS WITH and BETWEEN .. AND ..

Sim­i­larly, a scan can be expressed with the gen­eral format:

image

where operator1 to oper­a­torN can be one of the allowed com­par­i­son oper­a­tors in a scan request :

=, !=, >=, >, <=, <, CONTAINS, NOT CONTAINS, BEGINS WITH, IS NULL, IS NOT NULL, BETWEEN .. AND .., and IN (…)

To learn more about the syn­tax and how to use DynamoDb.SQL, take a look at the Get­ting Started guide here.

 

Links:

DynamoDB APIQuery­ing and Scan­ning

DynamoDB – Query­ing and Scan­ning using low-level Ama­zon­Dy­namoD­B­Client

DynamoDB – Query­ing and Scan­ning using Table helper class

DynamoDB – Query­ing and Scan­ning using high-level DynamoD­B­Con­text

Share