Well, first of all, normalization in a relational database is not an absolute goal. There are certainly situations where maintaining a denormalized table or column does make sense from a performance perspective.
Document databases, for the most part, don't have joins at all. Instead, you must write code that simulates a join, if you need one. The performance cost of a join in a relational database is more than made up for by the convenience it provides, especially if the fields that participate in the join are properly indexed. If you're going to need a join anyway, you might as well do it in a system that is specifically designed to work with joins.
Relational databases benefit from decades of research and refinement, and are supported by a well-developed body of knowledge from a robust community of users. Despite the object-relational mismatch, relational databases are nevertheless well-suited for business applications, which comprise at least 90 percent of the active software development in industry.
The so-called scalability limitations of relational databases are frequently overstated; such databases can be terabytes in size and support billions of records. You only need a big-data solution when your data sizes get into the hundreds of terabytes or petabytes range. A relational database can still handle the job 95 percent of the time.
One of the possible solutions would be to add a route such as https://example.com/user/<id>/avatar which would redirect the browser to the actual avatar.
For instance, if the real avatar is stored at https://linkedin.com/avatars/40bd001563085fc35165, your website will only store this URI once, in users
document, associated with the user 123
. Everywhere in the user interface, i.e. in all entities such as comments, the avatar will be implemented like this:
<img src="https://example.com/user/123/avatar" alt="..." />
During a HTTP request to https://example.com/user/123/avatar, the server will load the stored URI and respond with:
HTTP/1.1 302 Found
Location: https://linkedin.com/avatars/40bd001563085fc35165
which would effectively force the browser to show the correct image.
Notes:
In terms of performance, there shouldn't be too much issues. The request is relatively fast to process, and uses only marginal bandwidth (unlike serving images yourself).
It is essential to use HTTP 302 and not HTTP 301; otherwise, users who changed avatars will sometimes continue to see the old avatar, possibly for a long time.
Proper client-side caching can be implemented to prevent the browser from requesting the same avatar over and over (usually, when changing an avatar, one wouldn't be surprised to still see the old one for several minutes on some sites).
Note that if you're experiencing this difficulty with the avatar, you'll probably have the same issue with other pieces of information as well, due to improper normalization/denormalization. While some NoSQL databases encourage you to duplicate data in order to make queries faster and guarantee data consistency within a document, this comes at a cost of not being able to easily change the data scattered all over your database. Therefore:
Make sure you understand when to duplicate data and where to reference a single piece of data from other documents.
When applicable, rely on techniques such as the one I presented here, which make it possible to store a piece of data once, while not referencing it directly in other documents. For instance, on Stack Exchange, the zone which displays a user shows not only the user's name and avatar, but also the badges, the geographical location, the link to the website and a signature. Since those data are not crucial for the website, they can be queried through AJAX after the page is loaded, meaning that a question/answer doesn't need to contain this information or link to it in any way.
Best Answer
Short answer
Yes, you can write a meaningful benchmark of a studied case, if you do it with care, and understand that if it's relevant for the particular case, it may not be for other cases. This is equally true when comparing the databases of the same type (relational database vs. another relational database) or the databases of different types.
No, you cannot write a benchmark which will magically prove that a specific database is ways better than another in every case, for every application.
Long answer
It's definitely possible to say that "moving from a database to another improved our site performance".
You measure the performance of the previous database through profiling or runtime statistics by gathering enough information about the queries and how fast they are.
You move the application to the new database.
You do the same measures.
You compare.
For example, if the full list of 3 182 432 products loaded in 2.834 s. on an old database and loads in 0.920 s. on a new database, given that in both cases, the application has an empty cache, it's a win: the new database improved your site performance concerning this query.
Now, as any performance metric, it's biased:
Agreed, the new query is faster. But wait, your DBA didn't know how to use the database you had before, so the query which loads all the products is not optimized. If you rewrite it like that, you would be able to load those products in 0.855 s. instead of 2.834.
Ok, you have a better result. But don't you think that it's unfair to compare a database with fresh data just flushed to a 10 years old database for which the last maintenance plan was run three years ago? By the way, don't you think you should have updated the database product at least once during the last four years?
Some queries are faster. Some are slower. How do you compute the average result to know that you gained performance overall when moving to the new database? Ok, the time you load all 3 182 432 products is faster. But does it matter, while the query is executed on the website only in a rare case when an administrator is performing some specific task he performed only two times in the last ten years? On the other hand, executing all queries on the home page for a fresh user wastes 0.281 s. with the new database, when it was 0.207 s. with the old database. This result matters much more, especially since those queries cannot be cached for a long time, and are executed tens of thousands of times per day.
Both databases must be tested on the same servers, same hardware, same structure. For example, you can't test one database on a single hard drive, and the other one on a RAID1 of two SSDs. When you migrate a large project to a new database, there are chances that you'll just host the new database on hundred other newly deployed rack servers, when the previous database will still remain on the previous machines.
To summarize, you can benchmark the database queries of an application, and obtain precise metrics. But then, you have to give a meaning to numbers. At this state, it's tempting to say that you gained site performance: otherwise, management would be angry to learn that you've spent thousands of dollars and months of work just to make things slower.
The most terrible mistake is to take those conclusions from the benchmarks and to conclude some stupidity like "Microsoft SQL Server is three times faster than Oracle": saying this is like saying that "Java is better than PHP". Define better. Better in what cases? For what sort of applications? For what team of developers?
More you interpret and generalize, more the thing becomes irrelevant and meaningless.
is meaningful for a developer, and precise enough to know what was tested, how, and what was the results. This answers your question number 2.
Sadly, it doesn't make any sense for the management. Instead:
is a pure marketing jibber-jabber, and, technically, doesn't mean anything, but surprisingly has a value for the management and marketing departments.
Finally, can we compare different types of databases? I would say it's totally possible. Let's say I have a website hosting large photos. Those photos are stored in
varbinary(max)
in Microsoft SQL Server 2005 (so I can't usefilestream
). I am concerned about the performance when loading those photos, so I decide to store the photos as files instead, using the file system as my new database. First, those files are stored on the same machine than the database. I profile the new solution, and obtain the result that shows that in my case, files are loaded 4% faster from file system than from Microsoft SQL Server. The benchmark is very clear. Now I can think about deploying a dedicated server optimized for direct file storage, rather than using the server optimized for Microsoft SQL Server.