The Art of SQL

The Art of SQL

Stephane Faroult

⭐⭐

  • IT

Book for advanced Python with many important concepts for writing queries, with an interesting military theme. I’ll give it a chance. Not saying I’ll finish it, but it seemed interesting. Next up will be Fundamentals of Data Engineering.

I’m pasting a dump from my work notes. Reading it there was tough; I lost track halfway through and stopped taking meticulous notes. The original idea was to turn this into a post. I didn’t learn much, it was a heavy read, but the author is skilled and explains clearly. I am keeping a few takeaways that will be useful, especially for building efficient queries. Pushed through to the end.

Notes

Performance depends, first and foremost, on a sound database design,and second, on a clear strategy and well-designed programs

1. Laying Plans

  1. Ensure Atomicity -> use IDs instead of descriptions/names to identify rows. You have to make sure that searching for, say, the customer, returns all the rows without worrying about misspelling or slow “like” statements
  2. Check Dependence on the Whole Key -> keep columns to a limit: e.g. if the same car models share the same information about car details, move them to another table that can be joined through the car model key. Don’t keep redundant data in the main table for performance reasons
  3. Check Attribute Independence -> separate the independent attributes, for example country code details, which can be stored in another table connected through a non primary key to the row. This further minimizes data redundancy.

2. Waging War

The key topic of this chapter is that SQL is a declarative language, so keep it separate from the procedural nature of business specifications.

3. Tactical Dispositions

Chapter about indexes and how they can be used to optimize read operations

4. Maneuvering

Examining complex queries and how they can be decomposed into smaller, simpler components.

  1. The size of the tables we are querying
  2. The criteria required to define the result set (see Filtering)
  3. The size of the result set
  4. The number of tables to be processed (pay attention to views on top of tables, hiding complexity)
  5. The number of concurrent users

5. Terrain

Just as a general may discuss tactics with the engineering corps, so the architect of an application can study with the database administrators how best to structure data at the physical level. Choosing your terrain (storage, table arrangement, etc.) can make the difference.

  1. Round Robin (just equally distributed in chunks) doesn’t provide any particular benefit
  2. Data Partitioning provides performance increases because there is logic related to the data (we often query data in the same month, for example, so it makes sense to partition by that)
  1. Hash: key-value mapping, very fast if partitioning by categorical data, useless for ranges, it doesn’t consider the distribution of the values
  2. Range:

Miscellaneous (lost track)

  1. Use NOT EXISTS for looking for rows in one table where there is no matching data in another
  2. DB links are obviously slow; do operations locally to avoid latency. No joins across them
  3. Nested trees are messy and I don’t see where I would use them
  4. To get case-insensitive behavior, the easiest way is to store first and last names in uppercase and then apply upper() to the search and not vice versa, so you can use indexes
  5. Watch out for LIKE with lpad and variable length, it can take a long time because the engine doesn’t know when it has finished. Better to use upper and lower bounds
  6. If you have dynamic inputs that could be null (e.g. a movie DB) you need dynamic queries. But watch for injection, use parameters
  7. Don’t trust unit tests. With or without an index it may seem the same because it’s fast, but one does 5k queries per second and the other 25. Think about that too. In his example, a noticeable problem is something at 10000 requests per second anyway; it depends, but it’s not my case right now
  8. You can do little about locks, but limit large updates if you know there are reads at the same time, and of course optimize the updates (e.g. truncate instead of delete if clearing the table, roll back ASAP, limit loops, use stored procedures)
  9. Because truncate bypasses so much of the work that delete performs, you should use caution. The use of truncate may impact your backups, and it may also have other side effects, such as the invalidation of some indexes. Any use of truncate should always be discussed with your DBAs
  10. “Unconventional” designs such as attribute/attribute value columns are often used to simplify schema construction, but the queries are a mess. Don’t use them unless you have a solid reason. Self joins are terribly slow
  11. Pivot tables can be used for pivoting and performing advanced tricks such as multiplying values
  12. Be warned: “creative SQL” is often a euphemism for ugly SQL. For example, adding values in the same column to avoid fixing the schema (as I have seen in Synapse)
  13. Aggregating by range (bands) requires building an artificial sort key to display results in the desired order (like we do in Power BI, we need a new key)
  14. When selecting a value such as the address from two places where it could be null, instead of using COALESCE which is dangerous (we may retrieve the address id from one side and the address country from another), I should use a CASE statement or a hidden sort key (UNION + LIMIT 1) to avoid confusion
  15. End users often have a surprisingly high level of tolerance for poor performance; or perhaps it would be more appropriate to say that their perception of slowness differs widely from that of someone who has a better understanding of what happens behind the scenes.