{"data":{"allMarkdownRemark":{"edges":[{"node":{"id":"df094608-f958-5bcd-b406-ea359067fbd8","frontmatter":{"category":"Coding","title":"PostgreSQL 12 - a precious release","date":"2019-10-29","summary":"Improved Common Table Expressions in recent release of Postgres","thumbnail":{"relativePath":"pages/postgres12-a-precious-release/elephant_cropped.jpg","childImageSharp":{"resolutions":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAWABQDASIAAhEBAxEB/8QAGQABAQADAQAAAAAAAAAAAAAAAAMBAgQF/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQIA/9oADAMBAAIQAxAAAAHuzwyh9NJUx1M1Cf/EABoQAAIDAQEAAAAAAAAAAAAAAAEDABESAhD/2gAIAQEAAQUC9ZwwnDAsaq5ZgM//xAAYEQADAQEAAAAAAAAAAAAAAAAAARICE//aAAgBAwEBPwGDmxaZbP/EABcRAAMBAAAAAAAAAAAAAAAAAAACEwH/2gAIAQIBAT8BoVU1MJqf/8QAGxAAAgEFAAAAAAAAAAAAAAAAADEBECAhQWH/2gAIAQEABj8CrPIwNM1Z/8QAHBABAAICAwEAAAAAAAAAAAAAAQARITEQQVFx/9oACAEBAAE/IVDbLPeEWs5BNbatDthqyfsUeMAiBon/2gAMAwEAAgADAAAAEL/Xfv/EABkRAQEAAwEAAAAAAAAAAAAAAAEAMUFRYf/aAAgBAwEBPxAOy4kkzet//8QAGREAAwADAAAAAAAAAAAAAAAAAAExEVFh/9oACAECAQE/EHnGb2IuHE//xAAdEAEAAgICAwAAAAAAAAAAAAABABEhMRBRYXGh/9oACAEBAAE/EFAAVogmhwCxZXVnre/cLABvFBlrzTMCB1e/kSbKO4RYmd3m4ZIf/9k=","width":292,"height":325,"src":"/static/5076cf686ef8d2a21a3a6da9bf016970/a2998/elephant_cropped.jpg","srcSet":"/static/5076cf686ef8d2a21a3a6da9bf016970/a2998/elephant_cropped.jpg 1x,\n/static/5076cf686ef8d2a21a3a6da9bf016970/99cce/elephant_cropped.jpg 1.5x,\n/static/5076cf686ef8d2a21a3a6da9bf016970/6e995/elephant_cropped.jpg 2x,\n/static/5076cf686ef8d2a21a3a6da9bf016970/968b1/elephant_cropped.jpg 3x"}}},"authorName":"Mariusz Nowak","authorDescription":"Mariusz is a Senior Software Engineer at AUTO1 Group.","authorAvatar":null,"headerImage":null},"html":"<p>The PostgreSQL team <a href=\"https://www.postgresql.org/about/news/1976/\">announced recently</a> a new release of the most advanced\nopen source relational database - PostgreSQL 12. As usual it comes with an impressive list of improvements\n(generated columns ♥️), one of them being long awaited by dozens of developers: <strong>improved Common Table Expressions</strong>.</p>\n<p>I should first explain what are the Common Table Expressions for those who are unfamiliar with them:\nthe CTE’s, often called <code class=\"language-text\">“WITH queries”</code>, are SQL constructs giving a possibility of creating <strong>temporal data views</strong> for a sake of a query execution.</p>\n<p>Essentially CTE is an additional query which results can be referenced in the subsequent CTE’s or the main query before which\nit is being placed. It should be clear enough with an example - here’s a sample query with two CTE’s taken from Postgres docs:</p>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">WITH</span> regional_sales <span class=\"token keyword\">AS</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token keyword\">SELECT</span> region<span class=\"token punctuation\">,</span> <span class=\"token function\">SUM</span><span class=\"token punctuation\">(</span>amount<span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span> total_sales\n    <span class=\"token keyword\">FROM</span> orders\n    <span class=\"token keyword\">GROUP</span> <span class=\"token keyword\">BY</span> region\n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> top_regions <span class=\"token keyword\">AS</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token keyword\">SELECT</span> region\n    <span class=\"token keyword\">FROM</span> regional_sales\n    <span class=\"token keyword\">WHERE</span> total_sales <span class=\"token operator\">></span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> <span class=\"token function\">SUM</span><span class=\"token punctuation\">(</span>total_sales<span class=\"token punctuation\">)</span><span class=\"token operator\">/</span><span class=\"token number\">10</span> <span class=\"token keyword\">FROM</span> regional_sales<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">SELECT</span> region<span class=\"token punctuation\">,</span>\n       product<span class=\"token punctuation\">,</span>\n       <span class=\"token function\">SUM</span><span class=\"token punctuation\">(</span>quantity<span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span> product_units<span class=\"token punctuation\">,</span>\n       <span class=\"token function\">SUM</span><span class=\"token punctuation\">(</span>amount<span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span> product_sales\n<span class=\"token keyword\">FROM</span> orders\n<span class=\"token keyword\">WHERE</span> region <span class=\"token operator\">IN</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> region <span class=\"token keyword\">FROM</span> top_regions<span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">GROUP</span> <span class=\"token keyword\">BY</span> region<span class=\"token punctuation\">,</span> product<span class=\"token punctuation\">;</span></code></pre></div>\n<p>Now we know what they are, but what purpose can they serve us? Well - we could parry here and say: for the same purpose as ordinary database views serve.\nThat’s of course a dramatic simplification - CTE’s are much more powerful and should not be treated as a simple database views.\nNevertheless I would like to keep the collation for the sake of this article.</p>\n<p>Database views are absolutely optional - one can simply substitute them with a subquery and achieve identical results.\nIndeed that’s what modern database engines do these days - once a database view is being used they inline it’s query as a subquery.\nWhy to bother then? We are able to deal completely without database views and even if we did use one the database engine would get rid of it anyway.</p>\n<p>What benefits do views give us then? And why the heck are they inlined?</p>\n<h3>The beauty of database views</h3>\n<p>The most appropriate explanation here is that database views help us achieve better readability.\nThey offer an elegant way of abstracting some parts of a database into a meaningful object, often matching closely with the domain.</p>\n<p>Instead of creating giant and ugly looking queries it is possible to extract some of its parts into an appealing view which is easier to browse and select data from. <strong>\"Divide and conquer\"</strong> rule in it’s true form.</p>\n<p>Still, we didn’t answer the fact that the underlying view’s query is most of the times <strong>inlined</strong> while it is being referenced. The reason is <strong>performance</strong> of course. Smart guys found out that lazy evaluation helps the optimizer a lot - by delaying the execution we could take advantage of a context of the actual query.</p>\n<p>This in turn allows many clever optimization techniques, like: pushing down predicates (<em>WHERE filters</em>), eliminating unnecessary <em>JOINS</em>, accessing only subset of columns etc.\nIn other words - a database is smart enough to do as little work as possible when evaluating database views, in the context of the issued query.</p>\n<p>Personally I love this pattern: aggregating all the data into views and letting a database to optimize my queries - these folks are really good in it and my queries are dead simple too.</p>\n<p>I have mentioned the CTE’s at the beginning, saying they are able to create temporal data views. I still conform to the comparison with database views - they both are in many cases similar.\nThe main difference is that CTE results are temporary and are reachable only in the context of a query which CTE is being part of.</p>\n<p>It may make sense to use a CTE in a place where a regular database view is not justified (e.g. it makes sense only in the context of a query and not in the whole domain), expecting similar behavior.</p>\n<h3>An ugly brother</h3>\n<p>Besides many remarkable advantages there’s at least one disadvantage which disqualifies CTE's for most use cases - before PostgreSQL 12 it was implemented as an <strong>optimization fence</strong>. What does it mean?</p>\n<p>Easy to imagine an example with a generic data view aggregating lots of data. If the view is then used to select just few records it could mean a tremendous waste of computation, if the aggregation is executed immediately.\nInstead the aggregation should be executed only on a small subset of data, which can be deduced from the outer query.</p>\n<p>Unfortunately such counter intuitive behavior was true for CTE’s for a long time - their results were <strong>materialized</strong> only to be accessible for the rest of the query afterwards.</p>\n<p>Not to blame anybody - the creators had quite good reasons to implement such behavior (i.e. guarantee of exactly one evaluation, possibility of a recursive CTE’s and more) but this still feels like focusing on corner cases instead of optimizing the happy path.\nThat’s why the community <a href=\"https://www.postgresql.org/message-id/flat/201209191305.44674.db%40kavod.com\">insisted for a long time</a> for changing the status quo by giving the possibility of disabling the fence and unlocking the full potential of CTE’s.</p>\n<h3>Game changer</h3>\n<p>The SQL gods listen to their prayers and here it is - PostgreSQL 12 with updated <a href=\"https://www.postgresql.org/docs/12/queries-with.html\">Common Table Expressions</a>.\nBy default, when few constraints are met, the queries will be inlined allowing joint optimizations.</p>\n<p>It is still possible to force the old behavior - by defining the CTE <code class=\"language-text\">AS MATERIALIZED</code> the engine would execute it immediately.\nIt is also possible to hint the optimizer that we definitely want the CTE to be inlined, e.g. when the CTE is being referenced twice the engine won't inline it by default.</p>\n<p>This is truly a game changer for many developers who care about their queries’ readability, allowing them to substitute not very well liked subqueries with elegant <code class=\"language-text\">“WITH queries”</code>.</p>\n<p>Don’t get me wrong - not every subquery should be immediately replaced, they still have their strengths and in some cases they should be chosen over CTE’s. It is just convenient to have two distinct tools in a toolbox, isn’t it?</p>","fields":{"slug":"/postgres12-a-precious-release/","tags":["postgres","postgres12","release","sql","cte"]}}},{"node":{"id":"24fd2709-272a-5811-a69c-7100924de21c","frontmatter":{"category":"Coding","title":"Serving JSON (almost) directly from database","date":"2019-10-29","summary":"Learn how to query JSON data from Postgres 12 to improve Java application's performance.","thumbnail":{"relativePath":"pages/serving-json-from-postgres/liberty.jpg","childImageSharp":{"resolutions":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAIDBAX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHryz0HUYxXEAP/xAAbEAABBAMAAAAAAAAAAAAAAAABAgMSIhAgIf/aAAgBAQABBQJw0SoKxLjVDPT/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAYEAACAwAAAAAAAAAAAAAAAAABIQAQIP/aAAgBAQAGPwJRGzn/xAAaEAEAAwADAAAAAAAAAAAAAAABABEhEDGB/9oACAEBAAE/IVEqq3yWWlcbozCOmOokIz//2gAMAwEAAgADAAAAEOAPAP/EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8QH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8QH//EABwQAQADAQADAQAAAAAAAAAAAAEAETEhQXGhwf/aAAgBAQABPxBIyYq1CL8uc5XU14YIGwTYJTDeFrX2G/k7OwjIAbIBek//2Q==","width":325,"height":325,"src":"/static/e0de7302edcea3d0b0c19a9d147b547a/a2998/liberty.jpg","srcSet":"/static/e0de7302edcea3d0b0c19a9d147b547a/a2998/liberty.jpg 1x,\n/static/e0de7302edcea3d0b0c19a9d147b547a/99cce/liberty.jpg 1.5x,\n/static/e0de7302edcea3d0b0c19a9d147b547a/6e995/liberty.jpg 2x,\n/static/e0de7302edcea3d0b0c19a9d147b547a/968b1/liberty.jpg 3x"}}},"authorName":"Mariusz Nowak","authorDescription":"Mariusz is a Senior Software Engineer at AUTO1 Group.","authorAvatar":null,"headerImage":null},"html":"<p>RESTful API’s are ruling the industry nowadays. They are very often associated with an extremely popular data format - JSON.\nIt is so popular that database creators decided to implement it directly in the database engines.\nAll modern databases offer JSON processing capabilities.\nLet’s have a look and see how can we make use of them to improve our application’s performance.</p>\n<h3>JPA or JDBC?</h3>\n<p>The typical choice for a Java application is to use JPA as the persistence layer abstraction.\nIt became the de-facto standard for a reason - it offers great flexibility and ease of use.\nUnfortunately it doesn't come without a price since we have to pay with degraded performance.</p>\n<p>It is a widely known fact that <strong>ORM’s impact performance</strong>, compared to pure JDBC.\nOn the other hand, relatively few are willing to use plain JDBC, considering the amount of additional work it requires.</p>\n<p>Let me demonstrate how to use JDBC to leverage the performance, with the help of modern Postgres features.</p>\n<h3>Demo time</h3>\n<p>I have prepared a <a href=\"https://github.com/auto1-oss/postgres12-json-demo\">demo application</a> running on Spring Boot which exposes example data from the <a href=\"https://github.com/pthom/northwind_psql\">northwind</a> database.\nThe data are exposed in three different ways.</p>\n<p>The baseline version simply exposes JPA entities:</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token annotation punctuation\">@GetMapping</span><span class=\"token punctuation\">(</span>path <span class=\"token operator\">=</span> <span class=\"token string\">\"/v1/orders/{order_id}\"</span><span class=\"token punctuation\">,</span>\n            produces <span class=\"token operator\">=</span> APPLICATION_JSON_VALUE<span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">public</span> <span class=\"token class-name\">Order</span> <span class=\"token function\">getEntity</span><span class=\"token punctuation\">(</span><span class=\"token annotation punctuation\">@PathVariable</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"order_id\"</span><span class=\"token punctuation\">)</span> <span class=\"token class-name\">Integer</span> orderId<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> orderRepository<span class=\"token punctuation\">.</span><span class=\"token function\">findById</span><span class=\"token punctuation\">(</span>orderId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">orElseThrow</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>The Order entity aggregates data from numerous database tables: <code class=\"language-text\">orders</code>, <code class=\"language-text\">order_details</code>, <code class=\"language-text\">products</code>, <code class=\"language-text\">customers</code>, <code class=\"language-text\">customer_customer_demo</code> and <code class=\"language-text\">customer_demographics</code>.\nYou could check the corresponding JPA mapping <a href=\"https://github.com/auto1-oss/postgres12-json-demo/tree/postgres-12/src/main/java/com/auto1/postgres12/jpa\">here</a>.</p>\n<p>Thanks to the magic of Spring the entity is being translated into a JSON response:</p>\n<div class=\"gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n  <span class=\"token property\">\"orderId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">10284</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"employeeId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">4</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"orderDate\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1996-08-19\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"requiredDate\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1996-09-16\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shippedDate\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1996-08-27\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipVia\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"freight\"</span><span class=\"token operator\">:</span> <span class=\"token number\">76.56</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipName\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Lehmanns Marktstand\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipAddress\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Magazinweg 7\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipCity\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Frankfurt a.M.\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipRegion\"</span><span class=\"token operator\">:</span> <span class=\"token null keyword\">null</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipPostalCode\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"60528\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"shipCountry\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Germany\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"orderDetails\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token property\">\"orderId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">10284</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"productId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">27</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"product\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">\"productId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">27</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"categoryId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">3</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"supplierId\"</span><span class=\"token operator\">:</span> <span class=\"token number\">11</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"productName\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Schoggi Schokolade\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"discontinued\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"quantityPerUnit\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"100 - 100 g pieces\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"unitPrice\"</span><span class=\"token operator\">:</span> <span class=\"token number\">43.9</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"unitsInStock\"</span><span class=\"token operator\">:</span> <span class=\"token number\">49</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"unitsOnOrder\"</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"reorderLevel\"</span><span class=\"token operator\">:</span> <span class=\"token number\">30</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"unitPrice\"</span><span class=\"token operator\">:</span> <span class=\"token number\">35.1</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"quantity\"</span><span class=\"token operator\">:</span> <span class=\"token number\">15</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"discount\"</span><span class=\"token operator\">:</span> <span class=\"token number\">0.25</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span>...<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span>...<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span>...<span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"customer\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token property\">\"customerId\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"LEHMS\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"companyName\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Lehmanns Marktstand\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"contactName\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Renate Messner\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"contactTitle\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Sales Representative\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"address\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Magazinweg 7\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"city\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Frankfurt a.M.\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"region\"</span><span class=\"token operator\">:</span> <span class=\"token null keyword\">null</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"postalCode\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"60528\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"country\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Germany\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"phone\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"069-0245984\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"fax\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"069-0245874\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"customerDesc\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n      <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">\"customerTypeId\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"AAAA\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"customerDesc\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"First demographic\"</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">{</span>...<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">{</span>...<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">{</span>...<span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">]</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>The demo project includes the p6spy library which gives an insight into the queries being issued against database.\nTurns out that <strong>three queries</strong> are required to load a particular Order - this means <strong>three database round trips</strong>.</p>\n<p>Of course we can force the ORM to join all the tables and fetch them in one hop, but this seems a not so elegant solution -\nit pushes the ORM to load duplicated data and the necessity of deduplicating them in-memory. Can we do better?</p>\n<h3>JDBC to the rescue</h3>\n<p>JDBC is always a choice if the solution could be expressed via SQL query. Luckily we can create one which matches our case perfectly:</p>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">WITH</span> products<span class=\"token punctuation\">(</span><span class=\"token string\">\"productId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"categoryId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"supplierId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"productName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"discontinued\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"quantityPerUnit\"</span><span class=\"token punctuation\">,</span>\n              <span class=\"token string\">\"unitPrice\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"unitsInStock\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"unitsOnOrder\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"reorderLevel\"</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> p<span class=\"token punctuation\">.</span>product_id<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>category_id<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>supplier_id<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>product_name<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>discontinued::<span class=\"token keyword\">boolean</span><span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>quantity_per_unit<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>unit_price<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>units_in_stock<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>units_on_order<span class=\"token punctuation\">,</span>\n                 p<span class=\"token punctuation\">.</span>reorder_level\n          <span class=\"token keyword\">FROM</span> products p<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n     orderDetails<span class=\"token punctuation\">(</span><span class=\"token string\">\"orderId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"productId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"product\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"unitPrice\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"quantity\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"discount\"</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> d<span class=\"token punctuation\">.</span>order_id<span class=\"token punctuation\">,</span>\n                 d<span class=\"token punctuation\">.</span>product_id<span class=\"token punctuation\">,</span>\n                 <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> to_json<span class=\"token punctuation\">(</span>p<span class=\"token punctuation\">)</span> <span class=\"token keyword\">FROM</span> products p <span class=\"token keyword\">WHERE</span> p<span class=\"token punctuation\">.</span><span class=\"token string\">\"productId\"</span> <span class=\"token operator\">=</span> d<span class=\"token punctuation\">.</span>product_id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                 d<span class=\"token punctuation\">.</span>unit_price<span class=\"token punctuation\">,</span>\n                 d<span class=\"token punctuation\">.</span>quantity<span class=\"token punctuation\">,</span>\n                 d<span class=\"token punctuation\">.</span>discount\n          <span class=\"token keyword\">FROM</span> order_details d<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\n     demographics<span class=\"token punctuation\">(</span><span class=\"token string\">\"customerId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"customerTypeId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"customerDesc\"</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> ccd<span class=\"token punctuation\">.</span>customer_id<span class=\"token punctuation\">,</span>\n                 ccd<span class=\"token punctuation\">.</span>customer_type_id<span class=\"token punctuation\">,</span>\n                 cd<span class=\"token punctuation\">.</span>customer_desc\n          <span class=\"token keyword\">FROM</span> customer_demographics cd\n                   <span class=\"token keyword\">JOIN</span> customer_customer_demo ccd <span class=\"token keyword\">on</span> cd<span class=\"token punctuation\">.</span>customer_type_id <span class=\"token operator\">=</span> ccd<span class=\"token punctuation\">.</span>customer_type_id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n     customers<span class=\"token punctuation\">(</span><span class=\"token string\">\"customerId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"companyName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"contactName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"contactTitle\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"address\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"city\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"region\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"postalCode\"</span><span class=\"token punctuation\">,</span>\n               <span class=\"token string\">\"country\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"phone\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"fax\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"customerDesc\"</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> c<span class=\"token punctuation\">.</span>customer_id<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>company_name<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>contact_name<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>contact_title<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>address<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>city<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>region<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>postal_code<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>country<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>phone<span class=\"token punctuation\">,</span>\n                 c<span class=\"token punctuation\">.</span>fax<span class=\"token punctuation\">,</span>\n                 <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> to_json<span class=\"token punctuation\">(</span>array_agg<span class=\"token punctuation\">(</span>to_json<span class=\"token punctuation\">(</span>d<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">FROM</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> <span class=\"token string\">\"customerTypeId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"customerDesc\"</span> <span class=\"token keyword\">FROM</span> demographics <span class=\"token keyword\">WHERE</span> demographics<span class=\"token punctuation\">.</span><span class=\"token string\">\"customerId\"</span> <span class=\"token operator\">=</span> c<span class=\"token punctuation\">.</span>customer_id<span class=\"token punctuation\">)</span> d<span class=\"token punctuation\">)</span>\n          <span class=\"token keyword\">FROM</span> customers c<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\n     orders<span class=\"token punctuation\">(</span><span class=\"token string\">\"orderId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"employeeId\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"orderDate\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"requiredDate\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shippedDate\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipVia\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"freight\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"shipName\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipAddress\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipCity\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipRegion\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipPostalCode\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"shipCountry\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"orderDetails\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"customer\"</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> o<span class=\"token punctuation\">.</span>order_id<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>employee_id<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>order_date<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>required_date<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>shipped_date<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_via<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>freight<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_name<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_address<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_city<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_region<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_postal_code<span class=\"token punctuation\">,</span>\n                 o<span class=\"token punctuation\">.</span>ship_country<span class=\"token punctuation\">,</span>\n                 <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> to_json<span class=\"token punctuation\">(</span>array_agg<span class=\"token punctuation\">(</span>to_json<span class=\"token punctuation\">(</span>d<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">FROM</span> orderDetails d <span class=\"token keyword\">WHERE</span> d<span class=\"token punctuation\">.</span><span class=\"token string\">\"orderId\"</span> <span class=\"token operator\">=</span> o<span class=\"token punctuation\">.</span>order_id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                 <span class=\"token punctuation\">(</span><span class=\"token keyword\">SELECT</span> to_json<span class=\"token punctuation\">(</span>c<span class=\"token punctuation\">)</span> <span class=\"token keyword\">FROM</span> customers c <span class=\"token keyword\">WHERE</span> c<span class=\"token punctuation\">.</span><span class=\"token string\">\"customerId\"</span> <span class=\"token operator\">=</span> o<span class=\"token punctuation\">.</span>customer_id<span class=\"token punctuation\">)</span>\n          <span class=\"token keyword\">FROM</span> orders o<span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">SELECT</span> to_json<span class=\"token punctuation\">(</span>orders<span class=\"token punctuation\">)</span> <span class=\"token keyword\">AS</span> json_body <span class=\"token keyword\">FROM</span> orders <span class=\"token keyword\">WHERE</span> orders<span class=\"token punctuation\">.</span><span class=\"token string\">\"orderId\"</span> <span class=\"token operator\">=</span> ?</code></pre></div>\n<p>The query looks verbose, perhaps a little enigmatic.\nIt is a bit long and therefore it could be overwhelming.\nHowever, on a closer look we could notice it isn't so much complicated - there are few idioms which make the query powerful.</p>\n<p>The good news is that the query generates the exact same JSON as the JPA endpoint provides - it is possible thanks to Postgres’ excellent support for JSON format.\nOur case is not sophisticated though - single <code class=\"language-text\">to_json</code> function is enough to deal with JSON objects and arrays.</p>\n<p>One can notice how the nesting has been realized: how to nest JSON objects and JSON arrays, e.g. the <code class=\"language-text\">orderDetails</code> or the <code class=\"language-text\">customer</code> into <code class=\"language-text\">order</code>).\nThe simple idiom (accordingly <code class=\"language-text\">to_json(...)</code> or <code class=\"language-text\">to_json(array_agg(to_json(...)))</code>) does the job.</p>\n<p>The database query could be adapted according to the caller needs - the response can be shrinked, making the query simpler and - most probably - even more effective.</p>\n<p>Worth noticing is that the join table <code class=\"language-text\">customer_customer_demo</code> has been mitigated in the end result, just like the JPA version does by using <code class=\"language-text\">@ManyToMany</code>.</p>\n<hr>\n<blockquote>\n<p><em>The query is flexible enough to substitute all JPA features we need.</em></p>\n</blockquote>\n<hr>\n<p>I want also emphasize the fact of CTE’s being used to decompose the query into logical parts.\nPersonally I find it elegant because it is easy on the eyes and it “scales” - meaning while our case gets more complicated (JSON aggregates more data, becomes deeply nested) our query gets longer instead of getting deeper.\nIf the query grows too long we can simplify it by extracting some it’s parts as database views.</p>\n<p>The CTE has one more advantage here: it gives a control over the keys visible in end resulting JSON (<code class=\"language-text\">order_id</code> becomes <code class=\"language-text\">orderId</code>).</p>\n<p>So we have a nice query which allows us to fetch required data in one hop in a format ready to be consumed by our clients.\nThis means no adjustments are required, therefore the Java implementation can be that easy:</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token annotation punctuation\">@SneakyThrows</span>\n<span class=\"token annotation punctuation\">@GetMapping</span><span class=\"token punctuation\">(</span>path <span class=\"token operator\">=</span> <span class=\"token string\">\"/v2/orders/{order_id}\"</span><span class=\"token punctuation\">,</span>\n            produces <span class=\"token operator\">=</span> APPLICATION_JSON_VALUE<span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">public</span> <span class=\"token class-name\">String</span> <span class=\"token function\">getRawBodyFromDatabase</span><span class=\"token punctuation\">(</span>\n            <span class=\"token annotation punctuation\">@PathVariable</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"order_id\"</span><span class=\"token punctuation\">)</span> <span class=\"token class-name\">Integer</span> orderId<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> jdbcTemplate<span class=\"token punctuation\">.</span><span class=\"token function\">query</span><span class=\"token punctuation\">(</span>JSON_QUERY<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">ResultSet</span> rs<span class=\"token punctuation\">)</span> <span class=\"token operator\">-></span> <span class=\"token punctuation\">{</span>\n        rs<span class=\"token punctuation\">.</span><span class=\"token function\">next</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">return</span> rs<span class=\"token punctuation\">.</span><span class=\"token function\">getString</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> orderId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>We didn’t use plain JDBC here but a <code class=\"language-text\">JdbcTemplate</code> which has a negligible overhead and it simplifies our code.</p>\n<p>Of course we could achieve similar results using plain JDBC (e.g. by using <code class=\"language-text\">PreparedStatement</code> directly) - without the use of Spring.\nEven then the necessity of extracting only a single field from the result set makes the solution less coarse than using JDBC in a usual way\n(in our case it would require managing at least three result sets).\nAll the complexity has been moved down into the query.</p>\n<h3>But I need a POJO!</h3>\n<p>Some folks could argue “I don’t want the JSON to be directly returned - I definitely need the POJO to make some processing over it”.\nThat's an absolutely fair statement! We can satisfy this requirement as well.</p>\n<p>Let’s point it one more time: our query produces the exact same JSON as the Order JPA entity has been translated into.</p>\n<p>This means we can use the resulting JSON and unmarshall it into an object of class <code class=\"language-text\">Order</code>.\nOf course the object won’t be tracked by the JPA whatsoever but we don’t need these capabilities - remember: we are serving persisted data and not mutating them.</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token annotation punctuation\">@SneakyThrows</span>\n<span class=\"token annotation punctuation\">@GetMapping</span><span class=\"token punctuation\">(</span>path <span class=\"token operator\">=</span> <span class=\"token string\">\"/v3/orders/{order_id}\"</span><span class=\"token punctuation\">,</span>\n            produces <span class=\"token operator\">=</span> APPLICATION_JSON_VALUE<span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">public</span> <span class=\"token class-name\">Order</span> <span class=\"token function\">getEntityNotUsingJpa</span><span class=\"token punctuation\">(</span><span class=\"token annotation punctuation\">@PathVariable</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"order_id\"</span><span class=\"token punctuation\">)</span> <span class=\"token class-name\">Integer</span> orderId<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> jdbcTemplate<span class=\"token punctuation\">.</span><span class=\"token function\">query</span><span class=\"token punctuation\">(</span>JSON_QUERY<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">ResultSet</span> rs<span class=\"token punctuation\">)</span> <span class=\"token operator\">-></span> <span class=\"token punctuation\">{</span>\n        rs<span class=\"token punctuation\">.</span><span class=\"token function\">next</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">return</span> <span class=\"token function\">unmarshall</span><span class=\"token punctuation\">(</span>rs<span class=\"token punctuation\">.</span><span class=\"token function\">getString</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">Order</span><span class=\"token punctuation\">.</span><span class=\"token keyword\">class</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> orderId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token annotation punctuation\">@SneakyThrows</span>\n<span class=\"token keyword\">private</span> <span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">T</span><span class=\"token punctuation\">></span></span> <span class=\"token class-name\">T</span> <span class=\"token function\">unmarshall</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">String</span> json_body<span class=\"token punctuation\">,</span> <span class=\"token class-name\">Class</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">T</span><span class=\"token punctuation\">></span></span> clazz<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> objectMapper<span class=\"token punctuation\">.</span><span class=\"token function\">readValue</span><span class=\"token punctuation\">(</span>json_body<span class=\"token punctuation\">,</span> clazz<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>This version is very similar to V2 but it introduces an additional step of unmarshalling.\nIt is also a great verification step which makes us sure the V1 and V2 results are identical.</p>\n<h3>Measure, measure, measure</h3>\n<p>So how are all the solutions performing?\nWe suspect the V2 version to be faster than the competitors.\nWe are also unsure about the V3 which requires additional unmarshalling phase - could it impact the performance badly?</p>\n<p>The demo project includes a JMeter configuration and a bash script which verifies the configurations.\nThe benchmark is always run against a fresh setup (db + app).\nThe app is running on java 11 with EpsilonGC turned on - this allows us to verify memory consumption of each solution.</p>\n<p>The requests are run in strictly defined sequence, fetching the orders one by one.\nThere’s a prewarming phase which issues 100 requests and then a profiling phase with 20k of requests.</p>\n<p>I have run the benchmark several times on a Macbook Pro 2018, the results are similar on each run.\nHere’s a summary of the most recent run:</p>\n<ul>\n<li>V1 took <strong>1 minute and 25 seconds</strong> to complete the benchmark, the docker container ended up using <strong>1762 MB</strong> (1.641 GiB) of memory.</li>\n<li>V2 took <strong>53 seconds</strong> to complete the benchmark, the docker container ended up using <strong>1710 MB</strong> (1.593 GiB) of memory</li>\n<li>V3 took exactly <strong>1 minute</strong> to complete the benchmark, the docker container ended up using <strong>1758 MB</strong> (1.638 GiB) of memory</li>\n</ul>\n<p>We can see the V2 outperforming the V1 by 32 seconds - that’s <strong>37% improvement</strong>. </p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/00907e6fc534a6e242f935607d2ec10b/eb351/benchmark_duration.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 60.79207920792079%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAABzklEQVQoz22TW0sbQRTH94tWUAQLRftmaYVC7ScoFgr60qdSaH31QcFCvaGmJoGkiZU21O1GN5vN3i+Znd1/5+zN3cSBH+fMzux/zmVGghhJkpTMDsZCyPIt7u/voKp3GI1UKIos5kOEoV/bS79LsyI8TuAHEYKAp3g+g2l5JZblwzSFtX14HkMQ0p5IHByTJKQiQsYiJDHD74GBl2+aNTbetkpebZJt5z6tNbH++gon56M0IKlINQhCkYKH65sxnr+4xFqNi4q9wOr6A/Sd7NGZmgnO1ozC7/YMdPumwKj42bzz00Dv2hQHW+j/ymy3Z0IbB5lgHMciXZZGyPkU/4YOtrb7c7wndvp496EHWfHw2IhF/SXOOVzXha5P4LmWOF3H0rNTLAqqtmB59QztziS/ATwVKaDSzaXsuAyN5hg/WnpKo/XgX7V1nDc00e1pHlFcXrWiF2nKRBTxdEEdefj05Y9gkCP8r4MM4X/eHWD74w06orZFmjVBStcwDGjaGI5NTdCwsHKCJyvHua2z8DTj+6n6uGDhUJR0MSdGgP3DIQ6+ZewfKqVfsHeg4K/sZoKVlElDmn9q05nOhdV3RDvKmW3boKbSiKIIjuPgP7PRWr4XqQUSAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Benchmark duration in seconds\"\n        title=\"\"\n        src=\"/static/00907e6fc534a6e242f935607d2ec10b/40fad/benchmark_duration.png\"\n        srcset=\"/static/00907e6fc534a6e242f935607d2ec10b/707e9/benchmark_duration.png 148w,\n/static/00907e6fc534a6e242f935607d2ec10b/649e0/benchmark_duration.png 295w,\n/static/00907e6fc534a6e242f935607d2ec10b/40fad/benchmark_duration.png 590w,\n/static/00907e6fc534a6e242f935607d2ec10b/b3fef/benchmark_duration.png 885w,\n/static/00907e6fc534a6e242f935607d2ec10b/eb351/benchmark_duration.png 1010w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<p>We can notice also a lower memory consumption on the V2 - it used <strong>52 MB</strong> (49 MiB) <strong>less memory</strong> than V1\n(noted the initial app’s memory usage which is 785 MB):</p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/b7b44c0c52b828e9c0a6cc8124d4857a/b0617/memory_consumption_table.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 15.815815815815814%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAoUlEQVQI13WMyw6CMBBF+f9PkhQw3ahAAgYSCAt2ItJaRN5dXKeNceckNzlnXg7nRzDmgvMAQcCID/B9Bs9zrWdZiiSJEUVn5MR5niKOLwjDE/HVuplF5FVVwCnLAk1zw7ouGMe3zTRNXx6xzDOG4YW2vdsdk75X6LrHz6WUkEJg2zY4dV3TUOBfaa3p4UBHAnrfyXco9YSgB4ZNz7iJ2f0AaFLdIFy73HYAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Memory consumption comparison\"\n        title=\"\"\n        src=\"/static/b7b44c0c52b828e9c0a6cc8124d4857a/40fad/memory_consumption_table.png\"\n        srcset=\"/static/b7b44c0c52b828e9c0a6cc8124d4857a/707e9/memory_consumption_table.png 148w,\n/static/b7b44c0c52b828e9c0a6cc8124d4857a/649e0/memory_consumption_table.png 295w,\n/static/b7b44c0c52b828e9c0a6cc8124d4857a/40fad/memory_consumption_table.png 590w,\n/static/b7b44c0c52b828e9c0a6cc8124d4857a/b3fef/memory_consumption_table.png 885w,\n/static/b7b44c0c52b828e9c0a6cc8124d4857a/b0617/memory_consumption_table.png 999w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/6101a2054a60731cc34de93dc5d69976/1a868/memory_consumption_chart.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 38.76146788990826%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB7ElEQVQozzWS228SQRSH+fP8C3z1wTeNIZJWY8Q+tKE1xodqDBa8tS/Gy5OmqTGmSq02xEShGG7lfimwC7uUsOwCy8znsOBJzlzOzHy/OWfGNxMCXdfpahp616Cvtempca1Wxx3b/DfXdZFSYltDtHYb0+hhGxo9XaPVbNJX87n55k3NhddN6QV+D6Cn5mM1flWXCLmIj2wFdye8aeG55Up2GxJtLIkZ8LSKt9dXLfSJHJvcK0Ai3mE1MeVdZsTHY50bGUVaAu2xkhBTgjnJWk7QcSSX4pLTgWRPCV9NLsR9nz/V8EdK3FcKj7dT3DyxCR8ZBLczBEtgOIKRM8Z2HA+4UYGQcn0iufwX0pbKrgPX88sbxr42ub1XY1NtehnNEIg7RH+abEbPuKuAVd2hcd5haKmTzHgQ6/PwyKRruVx5q5HVJrxPDVnZ7yKEAn47bHJrt8qWAj6PLIE/TEI7ee4UVcZikbLjzKsqCEey7ESzGMYYfyBOoThg/6DOeiixAB5+aRB4UWGjDJFwGv+JQ/i7wXo4z6qqq7sEuu7M6x9Fcjx5lqNnOFxb+UVeAT8cNFjbOlVAgc9QC6mSSckSVKsXJNtDzi9c0mddsoMpcvltZjMxfyGKZZNypc90KviTbKlSTGipM+ms7n2rf9gTOwkX5RGhAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Memory consumption comparison\"\n        title=\"\"\n        src=\"/static/6101a2054a60731cc34de93dc5d69976/40fad/memory_consumption_chart.png\"\n        srcset=\"/static/6101a2054a60731cc34de93dc5d69976/707e9/memory_consumption_chart.png 148w,\n/static/6101a2054a60731cc34de93dc5d69976/649e0/memory_consumption_chart.png 295w,\n/static/6101a2054a60731cc34de93dc5d69976/40fad/memory_consumption_chart.png 590w,\n/static/6101a2054a60731cc34de93dc5d69976/b3fef/memory_consumption_chart.png 885w,\n/static/6101a2054a60731cc34de93dc5d69976/301c0/memory_consumption_chart.png 1180w,\n/static/6101a2054a60731cc34de93dc5d69976/1a868/memory_consumption_chart.png 1308w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<hr>\n<blockquote>\n<p><em>Worth noticing: the V2 version does not leverage Hibernate at all therefore we could minimize the memory footprint even more by excluding the JPA dependencies.</em></p>\n</blockquote>\n<hr>\n<p>Let’s have a look at response times:</p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/73c8b2f75166508b24cc53407109875b/13a80/response_time_table.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 11.15107913669065%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAYAAABYBvyLAAAACXBIWXMAAAsSAAALEgHS3X78AAAAhElEQVQI1z2Muw6CQBBF+f9v0cRlkdibGAE11Gohsj5Acd9ibK6zW1ic3Mk5ySRsdURaNEhLAV61YMUZfHNBRsy3N+R1R63FdLmn1sTGK0H9Su4Atj5hRkyoL3YCyb1/4jEoSG3hxy+kcXgpC2U8rP9EgtNujE7RHZDaYZAG2r7/G378APwJj8zXTZkxAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Response time summary\"\n        title=\"\"\n        src=\"/static/73c8b2f75166508b24cc53407109875b/40fad/response_time_table.png\"\n        srcset=\"/static/73c8b2f75166508b24cc53407109875b/707e9/response_time_table.png 148w,\n/static/73c8b2f75166508b24cc53407109875b/649e0/response_time_table.png 295w,\n/static/73c8b2f75166508b24cc53407109875b/40fad/response_time_table.png 590w,\n/static/73c8b2f75166508b24cc53407109875b/b3fef/response_time_table.png 885w,\n/static/73c8b2f75166508b24cc53407109875b/301c0/response_time_table.png 1180w,\n/static/73c8b2f75166508b24cc53407109875b/13a80/response_time_table.png 1668w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<p>Once again we are able to notice improved throughput as well as lower latency.</p>\n<p>The plot confirms that as well (cropped for brevity):</p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/609ca54ea332fb5f16d9c48de682d24f/4fbf1/response_time_plot.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 42.516069788797054%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsSAAALEgHS3X78AAAA60lEQVQoz6WS227EIAxE+f/v7G4gbIAQrgEyNaTdVdX2oaml0QEsWcPIbF1XpJQQQkCM8TJjTHBagfVhvY7j+Bd7Fe9eA1tro3mJ4wxkt50DR6PW0byq7jNvhgbmfFr/sP1XflZ3GPQM5p1D2zNK9CgpkPwX7dGRfmBwyKREuUVr4LXEZjXYwt+gxA0PfscyT5D8RuSDiqjozS4ztJywLgJ6flFLjoe4w5oFxijalgxWSkGlDGqjHMl2qW1wL3Wwv/sQoc06vlko65PtyUb/3fcysmSzlFDagAsBowT4RI6s/b6bpF938HmPeAfpVL+J2Dl0mAAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Response time percentiles plot\"\n        title=\"\"\n        src=\"/static/609ca54ea332fb5f16d9c48de682d24f/40fad/response_time_plot.png\"\n        srcset=\"/static/609ca54ea332fb5f16d9c48de682d24f/707e9/response_time_plot.png 148w,\n/static/609ca54ea332fb5f16d9c48de682d24f/649e0/response_time_plot.png 295w,\n/static/609ca54ea332fb5f16d9c48de682d24f/40fad/response_time_plot.png 590w,\n/static/609ca54ea332fb5f16d9c48de682d24f/b3fef/response_time_plot.png 885w,\n/static/609ca54ea332fb5f16d9c48de682d24f/4fbf1/response_time_plot.png 1089w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<p>Personally I am very well satisfied with the V3 results - the memory consumption being at the same level as the JPA it still offers satisfying performance, nearly as good as the V1.\nIt proves that the unmarshalling does not impact the performance as badly as we might expect.</p>\n<p>I really encourage readers try running the benchmark and share their own results!</p>\n<h3>Postgres 12 exclusive</h3>\n<p>Last words about the database: the results are reproducible currently only on Postgres 12,\ndue to <a href=\"/postgres12-a-precious-release\">recent improvements in Common Table Expressions</a>.</p>\n<p>I have had a run on Postgres 11 and the V2’s performance was… horrible - I had to shorten the benchmark 10 times to make it finish in a reasonable time.\nHere are the results I got:</p>\n<p><a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/1f9adc4fa288d49948eed727adf6be02/25720/postgres11_plot.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 590px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 26.254180602006688%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAAAsSAAALEgHS3X78AAAAfElEQVQY06WQ4Q7DIAiEff/HraIIhSvMLWuamP2YyeWLd0KEwsxIicifUvAglForzBx53D2Eh8LDD65yqHA0PA7YqWGecNsoM7d9bitXGSg5LlGLsTt6J4z49od3tVbfWduQXn0KzxnGwJzfXczbXpKZERFEdb17UhY17hdUJojcyMhn+QAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n    ></span>\n    <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;\"\n        alt=\"Response time percentiles plot\"\n        title=\"\"\n        src=\"/static/1f9adc4fa288d49948eed727adf6be02/40fad/postgres11_plot.png\"\n        srcset=\"/static/1f9adc4fa288d49948eed727adf6be02/707e9/postgres11_plot.png 148w,\n/static/1f9adc4fa288d49948eed727adf6be02/649e0/postgres11_plot.png 295w,\n/static/1f9adc4fa288d49948eed727adf6be02/40fad/postgres11_plot.png 590w,\n/static/1f9adc4fa288d49948eed727adf6be02/b3fef/postgres11_plot.png 885w,\n/static/1f9adc4fa288d49948eed727adf6be02/301c0/postgres11_plot.png 1180w,\n/static/1f9adc4fa288d49948eed727adf6be02/b5a53/postgres11_plot.png 1770w,\n/static/1f9adc4fa288d49948eed727adf6be02/25720/postgres11_plot.png 1794w\"\n        sizes=\"(max-width: 590px) 100vw, 590px\"\n      />\n  </span>\n  </a></p>\n<p>You can give it a try - the demo app is prepared to allow a quick switch to Postgres 11.</p>\n<h3>Summary</h3>\n<p>The query we have prepared enables fine control over the data being fetched from database.</p>\n<p>We are no longer restricted to tabular data - we could easily fetch complex data graphs, even manipulate them to match the desired format.\nWe did it keeping the solution maintainable and very effective in terms of throughput.</p>\n<p>It is still unknown to me what is the main source of latency in the JPA version: either is it the additional round trips or the internals of Hibernate.\nI see the topic interesting to explore.\nPerhaps some day we’ll get an ORM which is able to load entity graphs using a single query.\nAny Hibernate devs reading here?</p>","fields":{"slug":"/serving-json-from-postgres/","tags":["jdbc","jpa","postgres12","json","spring boot"]}}}]}},"pageContext":{"slug":"/tags/postgres12","tag":"postgres12","categories":["Architecture","Coding","DevOps","Engineering","ProjectManagement","QA","Social","TechRadar"]}}