DynamoDB cannot store empty strings
forums.aws.amazon.com
forums.aws.amazon.com
Would you like more insider advice on using DynamoDB? My startup Level Money used it as a primary data store and has kept it throughout our lifespan. We're migrating away from it now, but I wouldn't necessarily discourage people from using it.
NEVER SCAN ONE TABLE AND UPDATE ROWS AS YOU ENCOUNTER THEM, OR USE NATIVE KEY ORDERING TO TRIGGER UPDATES ANYWHERE ELSE!
Secretly DynamoDB is just a bunch of SQL databases with floating masters, or so we surmise. If you iterate across things in native order without randomization and at a very high speed then you will overload individual shards. You can end up at 10X write provisioning and still get rate limit responses. Randomizing the traversal of the keyspace fixes this.
Which is yeah, really really bad for sufficiently large datasets. You have to get creative to randomize it sufficiently in some cases.
Still, it's quite nice to have something like DynamoDB handling your scaling early on. It's a surprisingly useful design for a database and keeps you rom over-relying on relational properties which eventually don't scale. It also forces you to develop a story for cross-table transactional queries and their failures quite early in your platform's life cycle. Forcing that discipline is almost always healthy.
If you're not careful though, it becomes frightfully expensive. Before we understood why we were rate limiting we panicked and ended up with >$12k/mo in DDB costs. Not really a sustainable cost for a very small company.
Have you evaluated Couchbase? I've been looking for an excuse to try it, but I usually just fall back on Postgres.
Or is it precisely that which you've changed your minds about? The managed-REST-DB approach?
I'm curious because I'm currently writing an app, and I've chosen Google Datastore as the DB backend, primarily because it's managed (no DB VM maintenance), and makes scalability easy.
It's not based on SQL, but the fact that the table is sharded and has the throughput characteristics you describe is well documented (i.e. not at all secret :p) http://docs.aws.amazon.com/amazondynamodb/latest/developergu...
The documentation also explains that scanning a table runs the risk of saturating the capacity of a partition (1):
> As a table or index grows, the Scan operation slows. The Scan operation examines every item for the requested values, and can use up the provisioned throughput for a large table or index in a single operation. (...)
> The larger the table or index being scanned, the more time the Scan will take to complete. In addition, a sequential Scan might not always be able to fully utilize the provisioned read throughput capacity: Even though DynamoDB distributes a large table's data across multiple physical partitions, a Scan operation can only read one partition at a time. For this reason, the throughput of a Scan is constrained by the maximum throughput of a single partition. (emphasis mine)
Whenever I take an important dependency on a product, I make it a habit to read or skim virtually all of the product's documentation from beginning to end. Documentation for complex technologies is something to study. It's served me very well and I'd recommend the practice to others. With this approach you'll find that you just "know" (or can quickly look up) things that tend to surprise other people. Even if not all of the knowledge is in your working memory, you'll have a vague recollection of reading "something about that" and will be able to come back quickly to what you read.
(1) http://docs.aws.amazon.com/amazondynamodb/latest/developergu...
https://web.archive.org/web/20130102210613/http://docs.aws.a...
Huh, worded slightly differently, isn't it? They DO allude to this perhaps being the case in https://web.archive.org/web/20121221003912/http://docs.aws.a... but it's not made clear at any point that scans will yield up keys neatly bundled by shard.
It is not the case even now that the scan operation is using your capacity to cause this, it's because of the way shards enumerate their keys and that is not done simultaneously and mixed for you before sending it. You can redirect write traffic to another table and still often exhibit a rate limit effect even though the scan isn't consuming writes for that table.
That, I think, is still quite surprising.
You can take for granted how great the docs are now, although I still submit that this aspect of the system is quite poorly documented. AWS in general is fantastic at conveying API endpoints and very poor at offering a new developer a narrative on how to use the product.
The reason that the docs are as good as they are now: people like me have been around yelling at Amazon for years to improve their documentation, and telling tech reps to better document things. I hope you in your capacity do the same. And I will continue to offer insights like this on forums like this precisely because there are lots of relatively new platform engineers here. It's one of the few things I _like_ doing on hacker news.
Personally, I find it to often be a complete non-answer wrapped up with a dismissive and insulting attitude.
This is in sharp contrast to the GCE documentation (which is exhaustive although often out of date) or the Azure documentation (imho best overall for technical use but the UI keeps fizzing around making that part of it useless).
SQL is a querying mechanism not an underlying storage protocol. Converting from DynamoDB syntax to SQL would be a bazaar choice for them.
If you look at the limitations of Dynamo it becomes fairly clear what they do. Nearest I can figure it is close to this:
Each hash key resolves to a number of possible servers the data can be on. Data is replicated across several of these servers. For redundancy. The hash key determines which shard to use.
On individual machines, each set of data is stored by a compound key of hash key and sort key (if there is a sort key). The data is probably stored on disk sequentially by sort key or close to it. They possibly use something like LevelDB for this.[1]
If you have Global Secondary indexes it is literally treated as a separate table that is replicated to automatically. This is why users were doing anyway so Amazon just made it easy.
For those of you who do not know dynamo well. There are three basic read operations GetItem, Query, and Scan. Scans CANNOT be sorted, this is an important implementation detail.
A query can hit all the records for a single hash key very quickly because all records with the hash key exist on the same hardware. And they can be sorted because as mentioned earlier they are sorted by key on storage. Which is why you cannot query on more than one hash key at once. And why you can query for exact sort keys, greater than, less than, or between but not non-sequential. Because for performance Dynamo will only return sequential records from a query.
Scans, nearest I can tell, are map reduce across all shards that your table might exist on.
In conclusion. DynamoDB is a key value store with compound keys where the records are stored in order by key.
[1] In fact, I would not be surprised if Dynamo is mapped on top of LevelDB.
> Each hash key resolves to a number of possible servers the data can be on. Data is replicated across several of these servers. For redundancy. The hash key determines which shard to use.
> On individual machines, each set of data is stored by a compound key of hash key and sort key (if there is a sort key). The data is probably stored on disk sequentially by sort key or close to it.
This is pretty much exactly correct. The hash key maps to a quorum group of 3 servers (the key is hashed, with each quorum group owning a range of the hash space). One of those 3 is the master and coordinates writes as well as answering strongly consistent queries; eventually consistent queries can be answered by any of the 3 replicas.
> They possibly use something like LevelDB for this.[1]
Sigh...if only. I don't remember the exact timeline but LevelDB either didn't exist when we started development or wasn't stable enough to be on our radar.
DynamoDB is this very elegant system of highly-available replication, millisecond latencies, Paxos distributed state machines, etc. Then at the very bottom of it all there's a big pile of MySQL instances. Plus some ugly JNI/C++ code allowing the Java parts to come in through a side door of the MySQL interface, bypassing most of the query optimizer (since none of the queries are complex) and hitting InnoDB almost directly.
There was a push to implement WiredTiger as an alternative storage engine, and migrate data transparently over time as it proved to be more performant. However, 10gen bought WiredTiger and their incentive to work with us vanished, as MongoDB was and is one of Dynamo's biggest competitors.
Ah! I knew it! It's an orchestration layer on top of a mysql layer with floating masters.
I remember back when DDB was first launched we all sat around at Powerset and tried to figure out how Amazon did it given the two pieces of information we were given: "it is not based off the dynamo paper" and "it is based off both open source and proprietary code". We figured it had to be MySQL or Postgres that they were referring to.
I didn't know you were completely bypassing the query layer though.
My phone corrected "MySQL" to SQL and before I noticed the edit window expired. My apologies for the error.
I'm slightly less surprised because it apparently bypasses the SQL optimization engine and goes straight to InnoDB (per the other post). I have seen people write key-value stores based on MySQL+InnoDB before (sometimes bypassing SQL entirely).
Why would I consider it for sub-millisecond latency tasks? Has something changed there I'm unaware of?
All of this databases, got hot partition issue. If you cause to many read/write to one server you run into issues. That's why key schema is very important in non-trivial use-cases.
Classic anti-pattern is to use date or other increasing number as prefix. It is also problem when you use S3.
1. Empty strings are straightforward to represent.
2. Not allowing them violates the principle of least surprise, which makes the service harder to use.
3. Not supporting them adds needless complexity to client applications.
4. An empty string has obvious meaning and a place in everyday applications.
I know it took people a while to get this originally. In the old days, for example, Fortran 'do' loops were always executed at least once, regardless of the values of the bounds. Nowadays we know better: you check the values at the top of the loop, not (just) the bottom, to handle the zero-iteration case correctly.
But now it should be burned into every developer's brain: counts can be zero, strings can be empty, lists can be empty, etc. etc. etc., and handling these cases correctly is critical. Zero is not a special case!!!
http://stackoverflow.com/questions/6852612/bash-test-for-emp...
http://docs.aws.amazon.com/amazondynamodb/latest/developergu...
> A map is similar to a JSON object. There are no restrictions on the data types that can be stored in a map element, and the elements in a map do not have to be of the same type.
> Maps are ideal for storing JSON documents in DynamoDB. The following example shows a map that contains a string, a number, and a nested list that contains another map.
http://docs.aws.amazon.com/amazondynamodb/latest/APIReferenc...
It is also listed as a Gotcha on the AWS Open Guide which trended on HN a few weeks ago.
I do agree that they could do a better job in their documentation explaining the difference between JSON spec and their JSON equivalent that they store. It is not clear that the JSON you post is not stored in the same exact way. They could be more clear about the types they append to your data (L, S, SS, N) and then reference the link I put above about the restrictions for each type.
If you think you're going to migrate an existing system to DynamoDB, then this is one of the things you need to plan for.
The workarounds for this are rather unappealing, perhaps heretical.
Only when it's the lesser of the super-evils you have to pick from. I'd pick Oracle over Progress(OpenEdge), but not much else :)
I use Oracle every day, because that is one of the options for our customers rely on to run their critical Fortune 500 infrastructure. The other being SQL Server.
I'd say that Oracle delivers quite much value for your money for many applications.
I have worked with all other relevant relational databases and also with a few nosql databases, in distributed systems and monoliths.
It's hard to make a recommendation that can be applied generically. The best answer is "It depends, and it's complicated"
One thing is sure. Nosql is not the future (quite the opposite) although sometimes -in rather special circumstances- the right solution. Graph databases are perhaps more interesting, and perhaps event sourcing, but the promises are way larger than the deliveries.
Edit. I forgot the obvious reason. You try to stay clear of the Dark Side.
I also wouldn't make a generic database recommendation :)
For all its drawbacks (and I'm not a DBA or developer) at least I don't have to participate in HN threads where people discuss the 10 buzzwordy-DB-but-not-a-DB trends-of-the-week to migrate your data to.. which will all be forgotten next week :)
Fortunately, now that I'm over a million years old I'm probably not going to freak out about it no matter how wrong it seems. I might relax my pro-NULL politics a bit though.
I would even say I've worked with some top-notch DBA's, and I've at times been insufferable in my defense of NULL as a concept, and the databases in question have dealt with a whole lot of data and made a whole lot of money -- yet somehow I didn't know this.
Yay HN. :-)
Edit: Specifically, I was using some pretty advanced aggregation stuff. At the time I used it, DynamoDB had zero aggregation whatsoever.
My new rule of thumb: Use plain databases for most things and only use DynamoDB if there's a precise feature in your system that it is well suited for.
DynamoDB is a horrible general use database.
The NOSQL model fits great with a Restful API layer. The process of getting and posting data over HTTP should be a lot simpler with Restful API/MongoDB when compared to relational database solution.
I know Restful APIs are not perfect either, so care to fill in the blanks of why its was the worst dev experience for you.
That said, we've run into issues with the partitioning. If we were given access to the partition information and the ability to reduce partitions when needed, that would solve those problems.
Unless you plan on handing amazon your money forever, you should always steer for agnostic solutions you have the ability to host yourself.
As much as it may not 'scale' if you manage to get a passive income with decent understanding of load, then purchasing hardware is almost certainly cheaper for you.
Cheaper is good, it means more return so you can invest that income in your new project (and pay amazon for easy scaling again, if you want). But removing that ability not only locks you into their platform which may change prices at any time... it also means you can't move to self-hosting when the time is right and save quite a lot of money.
It doesnt use a unique database model that no other DB supports. Its based on NOSQL and it should be simple enough (with effort of course) to export a DynamoDB document store to another NOSQL solution.
Migrating database solutions is really quite expensive in terms of time. I've done it twice and it's not something to take lightly. The usual recommendation is to never migrate database solutions unless there is a catastrophic problem with continuing with the current.
NOSQL database on the other hand, completely different scenario. Exporting is a much more steamlined process. Again, its not magic, there is effort, but it is possible.
Just because you or your company are risk averse or strapped for cash, doesn't mean it's impossible to export a database. All the databases mention have export/import operations available, and as I said you are not locked into AWS if you do not wish to be.
Oh and don't assume my history thanks, you know nothing of it.
I'm going to attempt to be constructive here, but of course I'm biased so please take it with a grain of salt.
I cannot look past the words you speak, they are how I form an opinion of you on the internet. I cannot see your history, I cannot see your face/body language. Your words are your personality, they show your experience.
What you've said reminds me of similar people I know who have a distinct lack of experience, so, I lump you into that category.
In an attempt to understand you better I have peeked into your comment history. I can honestly say that I've not seen as much arrogance and bitterness for quite some time on hackernews.
Instead of trying to be snide and assuming you're better than people, or trying to passive-aggressively "win" a conversation.. Why don't we try to extract as much understanding or knowledge from every interaction on HN as possible.
most people on hackernews have some strong technical background, we have people here who are absolutely the forefront of their industry posting as regular users (Bryan Cantrill and Branden Gregg come to mind) which is absolutely humbling.
Now, with that out of the way, I invite you to read the topic.
"DynamoDB cannot store empty strings"
contrast that to your comment
>"NOSQL database on the other hand, completely different scenario. Exporting is a much more steamlined process."
NOSQL solutions aren't comparable if they handle types differently, they suffer most, if not all, of the conversion problems of relational databases.
The problem I faced when converting database solution was always types... Triggers, views and other relational-isms are a one-time investment fix.. converting types can easily lead to corruption of a few columns for a few rows.. how do you check that?
The answer is writing a lot of tests, and doing things especially carefully and incrementally.
and also, optimising for more revenue is not being cash-strapped, it's being wise enough to be able to reinvest capital in a new venture.. it's incredibly unwise to throw money up the wall for no reason other than it would cost a lot more to switch away due to vendor lock-in. (which is a reason not to move in of itself) which is what I'm warning about.
You speak in absolute terms that are simply not true. Choosing DynamoDB as your datastore does not mean you have to pay Amazon forever. Databases can be exported successfully. Costs can vary dramatically so don't assume it will blow the budget.
Amazon has a large repository of documentation in regards to exporting data and there is huge online community for AWS support and third-party tools. If you are as experienced as you claim to be, you would know these are big factors when choosing a platform to serve your data.
These benefits along with an incredible array of services, reliability, security, ease of configuration, reduced licensing costs, scalability and support coupled with the wealth of talented people available who are well versed in AWS would be enough to persuade most companies towards this choice. Thus why it is the most popular choice to host data at the moment and why most companies are moving away from in house databases. Thats not an opinion, thats fact.
What I like about DynamoDB is that you can scale the table easily. You don't need a dedicated DBA to maintain your database.
For what I don't like
1. You pay for what IOPS you allocated 2. You can't share free IOPS to other tables 3. Getting a snapshot of the whole DB is impossible, DB backups are not transactional 4. Use EMR or DataPipeline for backups 5. If you reach your IOPS limit, you need to retry your writes/updates instead of delayed ack's. Others uses libraries that limits writes but its per server and doesn't account the free writes on other servers since the accounting is on the client level
Yep, it is a classic, BUT (just in case): https://news.ycombinator.com/item?id=12426315
Don't use Dynamo unless you for some reason have to. It's half assed and not getting many updates.
As a workaround, if the database supports unicode, then store a "zero width space" for a blank string.
Can anyone explain to me why this isn't a bizarre question? They can't imagine a use-case for empty strings on their own?
It might be annoying but it's super easy to work around. It makes sense to not store empty strings, they provide no value and it would only take up space.
`""`, just like `NULL`, is semantically difference from absence of record.
I did this to convert some String Sets (SS) in my database to String Lists (L). I almost did this same thing to fix the empty String issue but didn't have the time to implement it yet.
http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/ama...
If you want a kludge for this, it's better to generate a longish random string (e.g., a UUID) to indicate an empty value.
One issue that might arise with altering historical data that I can imagine would be if it was ever necessary to restore from backup and your backup was made before you later added the zero width space, and then you forget to add the zero width space again when you restore from backup a few months down the road. But with proper documentation and procedures that shouldn't happen.
string_to_store = userstring + extra space
dynamo.store(key, string_to_store)
...
stored_string = dynamo.retrieve(key)
user_string = stored_string - extra space
That way the user puts a string in and gets the same string out. No problem.I'm guessing you have to have it in a form you can search it (so you can't just GZIP it or something like that)?
I'm interested in abstract concepts, not "I'm trying to port from Oracle/Mongo/whatever and this is how it works". Assume your designing against some generic record store.
I'm having a ton of trouble thinking of a case where that's a big problem (again, ignoring trying to save time in porting) and I was wondering if someone could provide me a few examples.
A null middle name means "we don't know their middle name, we added it to the schema after that user signed up or didn't ask them". An empty string means they explicitly don't have a middle name.
[1] key present, value undefined or null or some other special type
[2] key present, value is empty object of its expected type
[3] key absent
In schemaless datastores where the value's content somehow determines its datatype, it can be difficult to enforce a distinction between scenarios [1] and [2]. Meanwhile, in an externally-schema'd datastore (like most RDBMS), you don't have option [3]. I am familiar with the practice of mapping "we don't have a known-good value for this" to omitting the key in an KV-store, while in an RDBMS that semantic meaning is mapped to a NULL instead.
> But my middle name IS "null"
In a relational table, all rows in the table have a "middleName" column. So you can't "omit" the column entirely for some rows like you can in a doc/KV store.
"NULL" in a relational DB is to store, in a table where every record has a "middleName" column, the concept of "missing key" from a key/value store type layout.
NULL is the relational DB's way of representing: "a record without a middleName key" exists here.
In what ways do you think the limitation is an incontrovertible issue?
It's an impedance mismatch with every programming language I personally know, which all permit the empty string. Even Erlang or Haskell, with their oddball strings that are actually lists, permit an empty/null list for this purpose. What might they be? Maybe it's a blank line from an array of chomped input lines, maybe it's a base case of a recursive operation (see also: you can't have an empty set, possibly related, maybe DynamoDB stores strings as lists...).
The point is, sometimes we have the empty string as a legitimate scalar value, so rejecting them creates extra work for the developer and feels like a POLA* violation, even if there's a solid underlying technical reason why it is so (and maybe there is, maybe it's due to a Merkle tree for the values, as suggested in the predecessor Dynamo's original paper). It's the kind of thing that leads people to develop wrappers for things that really shouldn't need them, which is a gateway drug into all sorts of unnecessary abstractions and extra work.
At the other end of the spectrum I've seen some hilaribad JSON structures, ones where a value might be absent, or null, or the empty string, or a real string, and these four things all have different meanings /o\.
* Principle of Least Astonishment.
Here's an example. Let's say a user is taking a survey and the last question is: "Please share any additional thoughts if you have them." A null could mean the user did not answer this question, probably because they haven't gotten to it yet. An empty string could mean the user was asked this question and actually didn't have anything to say.
But in that case how can you tell the difference? I mean if they never clicked in the field or tabbed into it and submitted the form is that meaningfully different from they clicked into it and didn't type anything?
I can think of ways to work around it (keep a boolean for 'was filled out', a number that means 'they got up to field 17', etc.) but I'm still not sure you can draw a conclusion of 'they skipped it' vs 'they didn't enter anything'.
I think the null vs empty argument works better when there are 40 boxes on screen at once. But again I'm not sure what semantic difference you'd find between 'they left it empty' and 'they never clicked into it'.
Second, in Dynamo you could chose the absence of a key to represent "never got here" and a key with a null value to represent "they left this blank". You don't need an empty string.
When you say "The user submitted an empty form field as their answer", you do have data. It's weird to use null for that.
Since you can leave a key absent in DynamoDB, it basically has two ways to say "data unknown" and no way to say "knowingly left blank".
You can repurpose null as you suggested, and it will work fine in isolation, but it will massively violate the principle of least surprise and could lead to painful bugs.
I haven't used DynamoDB enough to tell if that applies here or not.
Either way, you'd still need to give a good reason for "this space intentionally left blank" because I'm not seeing much in the well of compelling reasons.
Many people have mentioned the idea of keeping track of if someone doesn't have a middle name versus you don't know their middle name. That makes more sense as an example (although I'm not sure how critical that is).
One of the first problems that you'll encounter if you use a DB with "" != NULL is at data display, because the natural display for NULL and "" are "an empty cell". Then you cannot tell if it is NULL or ""... then you must display something else for NULL... then...
You have no such problem if "" is NULL, an empty cell always means NULL
Data display with NULL != "" is easy, do what SSMS does and italicise/otherwise highlight the NULL.
What problems does "" being different to NULL cause?
My experience is the exact opposite.
You should instead use a list of all possible solutions, or a sublist of that list (if you only need one solution) because then the empty list can indicate there are no solutions.
If you then want to do something you can iterate over the list: This will protect you from "null pointer" exceptions, promote more functional programming, and is usually less code as well.
js: if(x !== null) { … }
q: $[not null x;…;'`oops]
versus: js: x.map((r) => …)
q: {…} each x0 <> NULL <> ""
They are all values that matter because they can exist.
Blank can have business meaning. Also, I suspect that there is a reason blank is separate from NULL in the ASCII table. They are different signals, and changing one to the other is fundamentally changing the meaning of the signal.
Blank often has business meaning on forms, like "leave this field blank to indicate the user has acknowledged the field but chose to enter a blank value" vs the "user never saw this field and no value was entered, or the system did not store a value for the user's input".
The old saying "NULL is not nothing"?
Also dynamo's capacity provisioning can be scaled up any time (although scaling up is slow-ish), but only down once per day, which means that unlike the promise of ec2 you end up having to essentially pay for your peak load at all times.
If I had it to do over again I'd have stuck with postgres, the only reason we used dynamo in the first place was to throw our boss a bone to soften our flat refusal to use Amazon Simple Workflow, which is an even bigger quagmire.
Totally agree on SWF. :)
I misconfigured some parameters and ended up with a big bill for a database that was doing pretty much nothing.
I don't see the upside of DynamoDB.
Wide column, no-sql data store where you pay for provisioned throughput, and storage over 25GB.
All maintence is taken care by Amazon, no sharding, scale, patching, or tuning required.
If you need a non relational data store for use inside an AWS deployment, you would be hardpressed to find a better alternative.
RDS Postgres supports HStore and JSON types.
1. have at minimum 2 instances 2. schedule backups 3. create and manage your db schema 4. manage users/roles
Admittedly RDS makes some of those tasks easy, but Dynamodb makes it even easier.
1. Create the table, provision read/write throughput 2. Create IAM role.
You need to back up data from Dynamodb, but as a measure to protect against user caused data loss, not AWS infrastructure failure dataloss.
That's the key, isn't it?
I've been trying to wrap my head around DynamoDB for something that wouldn't necessarily live inside AWS and it seems like an awful lot of trouble.
But I guess if you're in the same AWS Region and you're doing high-volume stuff then the cost savings probably get compelling real fast.
[Source/Disclaimer: I work on Google Cloud Bigtable.]
I'm slowly migrating a self-hosted MongoDB database to DocumentDB and things are going pretty well. The only thing missing for me is aggregation and transparent encryption, but they are working on those.