<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nikita Kutsokon</title>
    <description>The latest articles on DEV Community by Nikita Kutsokon (@nikita_kutsokon).</description>
    <link>https://dev.to/nikita_kutsokon</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2830019%2F2e23c9ae-5db5-46cc-bc89-d4166c868cfa.png</url>
      <title>DEV Community: Nikita Kutsokon</title>
      <link>https://dev.to/nikita_kutsokon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nikita_kutsokon"/>
    <language>en</language>
    <item>
      <title>Databases: Concurrency Control. Part 1</title>
      <dc:creator>Nikita Kutsokon</dc:creator>
      <pubDate>Fri, 25 Apr 2025 12:02:54 +0000</pubDate>
      <link>https://dev.to/nikita_kutsokon/databases-concurrency-control-part-1-10j0</link>
      <guid>https://dev.to/nikita_kutsokon/databases-concurrency-control-part-1-10j0</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Imagine you're working in a busy office with multiple people trying to update the same spreadsheet at the same time. One person is adding new information, while another is making changes to existing data. At the same time, others are just looking at the document, but they need to see the latest, accurate version of the data. In this situation, how can we ensure that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;People making changes don’t accidentally overwrite each other’s work ?&lt;/li&gt;
&lt;li&gt;People who are just reading the document always see the most up-to-date version, without waiting for someone else to finish their work ?&lt;/li&gt;
&lt;li&gt;The document doesn't end up in a jumbled state ?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, imagine this happening in a database, where multiple users or applications are trying to read from and write to the same tables at the same time. The challenge is even bigger in this case because databases are designed to store huge amounts of data, and many transactions need to happen simultaneously.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Is Concurrency Hard in Databases ?&lt;/strong&gt;&lt;br&gt;
When multiple users or processes are interacting with the database at once, several things can go wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data consistency issues&lt;/strong&gt; - One user might see outdated information because another user is changing it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Locking problems&lt;/strong&gt; - If one transaction locks a row, other transactions might have to wait, leading to delays and frustration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency anomalies&lt;/strong&gt; - Without the right mechanisms in place, transactions could lead to inconsistent results, such as one user overwriting another’s work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Databases need to figure out how to let users work simultaneously without blocking each other, and also make sure the data stays consistent and correct no matter how many people are using it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is MVCC ?
&lt;/h2&gt;

&lt;p&gt;The solution lies in using techniques that allow each transaction to see a consistent snapshot of the data, without interfering with other transactions. One of the most powerful and widely used techniques in modern databases - is called &lt;strong&gt;Multiversion Concurrency Control&lt;/strong&gt;. It is a method that enables multiple transactions to access the database simultaneously without blocking each other. This is accomplished by creating multiple versions of a piece of data, instead of having just one active version at any time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tyxkr3hgmmqzvt1vfo0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tyxkr3hgmmqzvt1vfo0.png" alt="Table with MVCC" width="584" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In an MVCC-based system, when data is updated or inserted, a new version of the row is created. However, if a transaction only reads the data without modifying it, it accesses the original version of the data. This ensures that read operations are not blocked by write operations, and write operations do not block reads. As a result, the new version of the data becomes visible only after a modification or insertion occurs, allowing concurrent transactions to work with different versions of the same data without causing interference. This approach enables databases to maintain data consistency and high concurrency while minimizing the need for locking resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example of MVCC in Action&lt;/strong&gt;&lt;br&gt;
Let's say three transactions, T1, T2, and T3, are operating on the same row in the database:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Transaction T1&lt;/strong&gt; reads a row and decides to update it. This creates version 2 of the row.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transaction T2&lt;/strong&gt; also reads the same row (before T1 has committed) and performs a different update, creating version 3 of the row.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transaction T3&lt;/strong&gt; reads the row as well and decides to insert a new value, creating version 4.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At this point, there are three versions of the same row, each with different updates from different transactions. The database now has to manage and ensure that the operations from these transactions do not interfere with each other. In the next parts of this article, we will explore how the database resolves conflicts when multiple transactions try to modify the same data. This conflict resolution ensures that data consistency is maintained and that transactions are isolated properly&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hidden Cost of MVCC: Bloat
&lt;/h2&gt;

&lt;p&gt;While Multiversion Concurrency Control offers many benefits, such as high concurrency and reduced locking, it comes with its own set of challenges. One of the most significant drawbacks of MVCC is bloat. In this section, we’ll explore what bloat is, how it occurs in MVCC systems, and its impact on database performance.&lt;/p&gt;

&lt;p&gt;Bloat refers to the buildup of unused, outdated, or "dead" data versions in the database, resulting from the creation of multiple row versions due to MVCC. As time passes, these obsolete versions accumulate and consume storage space, leading to inefficient resource usage. As bloat increases, it introduces several negative effects on both storage and performance. The presence of outdated data versions creates inefficiencies that can worsen over time. If left unmanaged, these inefficiencies can significantly degrade the overall health and performance of the database. Let’s explore how bloat can impact the database’s functionality in more detail:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increased Storage Usage&lt;/strong&gt; 💾🫠&lt;br&gt;
The primary cost of bloat is that it leads to increased disk space usage. As new versions of rows accumulate and old versions remain in the database, the overall size of the database increases. This means more disk space is needed for storage, and more memory is required to process queries that involve large amounts of outdated data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Slower Query Performance&lt;/strong&gt; 🏃😶&lt;br&gt;
As bloat accumulates, queries may need to process more data than necessary. Even though old versions of rows are no longer needed, they still have to be read and checked during queries, especially if they are not cleaned up properly. This can slow down query performance, particularly for read-heavy operations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increased Maintenance Overhead&lt;/strong&gt; 🛠️☹️&lt;br&gt;
Managing and cleaning up bloat introduces additional complexity. While newer versions of a row are easily accessible, dead tuples need to be removed periodically, which requires an active maintenance process. Without proper cleanup, the database can become inefficient and slow down over time.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Enter VACUUM 🦸🌟
&lt;/h2&gt;

&lt;p&gt;To combat the negative effects of bloat, databases like PostgreSQL use a process called VACUUM. VACUUM is designed to reclaim storage space by removing outdated or "dead" versions of rows that are no longer needed. Over time, as multiple versions of rows accumulate due to ongoing transactions, the database can become inefficient and sluggish. Without VACUUM, this bloat would continue to increase, leading to wasted storage and slower query performance. VACUUM helps keep the database running efficiently by removing these obsolete row versions and maintaining transaction visibility, ensuring that ongoing operations aren't impacted by outdated data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvtghkykc7ih0zvkklnt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvtghkykc7ih0zvkklnt.png" alt="MVCC cleaning" width="800" height="719"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Think of VACUUM like a housekeeper in a busy office. Just as employees move documents around, updating or discarding them, the office can become cluttered if old, irrelevant papers are not cleared away. VACUUM performs a similar role, ensuring the database remains tidy and efficient. PostgreSQL offers several types of VACUUM processes to manage this cleanup. The standard VACUUM reclaims storage and removes dead rows without locking the table, allowing the database to continue operating with minimal disruption. The VACUUM FULL, on the other hand, not only removes dead rows but also compacts the table by physically rewriting it, reducing its disk space usage. While standard VACUUM is run frequently as part of regular database maintenance, VACUUM FULL is typically used when a large amount of space needs to be reclaimed, such as after large deletions or updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  How MVCC and VACUUM Work Together 🤝
&lt;/h2&gt;

&lt;p&gt;MVCC and VACUUM work together to maintain PostgreSQL’s performance and consistency. MVCC enables multiple transactions to run concurrently by creating new versions of data when updates or inserts occur, allowing reads to access the original version without waiting for writes. However, this leads to the accumulation of outdated row versions, causing bloat. VACUUM addresses this issue by periodically removing these "dead" versions, reclaiming storage space, and ensuring the database remains efficient. Together, MVCC allows high concurrency while VACUUM prevents performance degradation, keeping the database both responsive and well-maintained.&lt;/p&gt;

&lt;h2&gt;
  
  
  Helpful Links 🤓
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Text resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.geeksforgeeks.org/what-is-vacuum-in-postgresql/" rel="noopener noreferrer"&gt;What is Vacuum in PostgreSQL ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.geeksforgeeks.org/what-is-multi-version-concurrency-control-mvcc-in-dbms/" rel="noopener noreferrer"&gt;What is Multi-Version Concurrency Control (MVCC) in DBMS ?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Video resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=xnps3zQCcZc" rel="noopener noreferrer"&gt;PostgreSQL Understanding Vacuum&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=TBmDBw1IIoY" rel="noopener noreferrer"&gt;PostgreSQL Internals in Action: MVCC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=iM71d2krbS4" rel="noopener noreferrer"&gt;Multiversion Concurrency Control (MVCC) Explained in Simple Terms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=meU2qKRzkCM" rel="noopener noreferrer"&gt;A Detailed Understanding of MVCC and Autovacuum Internals in PostgreSQL 14 - Avinash Vallarapu&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>database</category>
      <category>systemdesign</category>
      <category>backenddevelopment</category>
    </item>
    <item>
      <title>Databases: Replication</title>
      <dc:creator>Nikita Kutsokon</dc:creator>
      <pubDate>Wed, 23 Apr 2025 10:11:52 +0000</pubDate>
      <link>https://dev.to/nikita_kutsokon/databases-replication-1cfp</link>
      <guid>https://dev.to/nikita_kutsokon/databases-replication-1cfp</guid>
      <description>&lt;h2&gt;
  
  
  Why Replication Matters
&lt;/h2&gt;

&lt;p&gt;Database replication plays a crucial role in ensuring that business systems remain resilient, responsive, and reliable. For modern companies, data is at the heart of nearly every operation — from handling customer transactions to running analytics and decision-making tools. If the primary database fails, even for a few minutes, it can lead to lost revenue, broken services, and a damaged reputation. Replication helps prevent this by creating and maintaining exact copies of the database (replicas) on other servers, often in real-time. These replicas can be used for &lt;strong&gt;failover&lt;/strong&gt;, meaning if the main system goes down, a replica can immediately take over with minimal disruption.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1i4jelrye19wzendhefb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1i4jelrye19wzendhefb.png" alt="Database replication" width="300" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Beyond disaster recovery, replication supports &lt;strong&gt;performance&lt;/strong&gt; and &lt;strong&gt;scalability&lt;/strong&gt;. In high-traffic environments, read-heavy operations (like showing product listings or dashboards) can be redirected to replicas, easing the load on the primary server. This is known as read scaling, and it's especially valuable for applications with many users or global reach. Replication also enables data locality — storing copies closer to users in different regions — which reduces latency and improves user experience. Additionally, developers and analysts can run heavy reporting or analytics on replicas without affecting the main production system, which ensures better system stability. In essence, database replication is a foundational practice for building systems that are fast, fault-tolerant, and future-ready.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqcaje2zu8ea3lwbhr37l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqcaje2zu8ea3lwbhr37l.png" alt="Read replicas for database" width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Replication Topologies
&lt;/h2&gt;

&lt;p&gt;In distributed systems, replication is a key technique used to enhance availability, fault tolerance, and performance. The structure and behavior of data replication are determined by the replication topology, which defines how data flows and is synchronized across multiple nodes. Each topology offers a different balance of consistency, latency, scalability, and complexity, making it suitable for various types of applications. Below are the main replication topologies, along with their advantages, disadvantages, and real-world examples:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Single-Leader&lt;/strong&gt;&lt;br&gt;
In a single-leader replication topology, one node, called the leader, handles all write operations, while one or more replica nodes handle read operations by copying data from the leader. This setup ensures strong consistency because all writes go through a single node, which makes it easier to reason about system state and resolve conflicts. However, the leader becomes a single point of failure—if it goes down, the system cannot process writes until a new leader is chosen. Additionally, write throughput is limited by the leader's capacity, and there may be read inconsistencies if the replicas lag behind.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5fgmhh8xfe787skl5qgt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5fgmhh8xfe787skl5qgt.png" alt="Single-Leader replication topology" width="800" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🤓 This topology is ideal for systems where strong consistency is a priority and write operations need to be tightly controlled, such as financial applications or systems where it is critical that all data changes are reflected correctly. It is also useful when read scalability is needed, as replicas can handle read-heavy workloads without affecting the leader's performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Multi-Leader&lt;/strong&gt;&lt;br&gt;
A multi-leader topology allows multiple nodes to accept write operations and synchronize with each other. This setup is particularly beneficial for geographically distributed applications, where users across different regions need to perform updates with minimal delay. By having multiple leaders, the system can offer better write availability and reduce latency for users who are far apart. However, this topology introduces the challenge of conflict resolution, as multiple nodes may try to write to the same data simultaneously, and syncing those changes becomes more complex. There’s also the risk of data divergence if synchronization between leaders is delayed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd9hq9qcpdz6e3rwpmw3l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd9hq9qcpdz6e3rwpmw3l.png" alt="Multi-Leader replication" width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🤓This topology is most useful for geo-distributed applications that require low-latency writes, such as collaborative platforms or social media apps where users across different regions need to interact and update data simultaneously without waiting for a central leader to process the changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Leaderless&lt;/strong&gt;&lt;br&gt;
In a leaderless replication topology, every node is equal and can accept both read and write operations. Consistency is typically achieved through consensus protocols, such as quorum-based approaches where a majority of nodes must agree on a change. There is no designated leader in this model, so the system avoids the single point of failure that exists in other topologies like single-leader. However, leaderless replication may introduce eventual consistency, meaning that data might not be immediately consistent across all nodes, especially in cases of network partitions or concurrent updates. Conflict resolution can also be more complex, especially as the number of nodes increases.&lt;/p&gt;

&lt;p&gt;Leaderless replication can be implemented in several configurations, each with its own advantages and trade-offs. Three common configurations are star, circle, and all-to-all:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Star&lt;/strong&gt; - In this setup, one node acts as a central hub that coordinates communication between other nodes. The central node may not necessarily handle all writes, but it ensures that the data is synchronized across all nodes. This configuration reduces the complexity of having every node communicate with each other but can introduce a single point of failure at the central hub if not managed properly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Circle&lt;/strong&gt; - The nodes are arranged in a circular fashion, where each node communicates with its immediate neighbors. When a write happens, it propagates through the circle of nodes until it is agreed upon by a majority. The circle setup helps distribute the load more evenly compared to the star configuration, but there is still potential for delays in synchronization due to the sequential nature of the communication.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;All-to-All&lt;/strong&gt; - In an all-to-all setup, each node communicates directly with every other node. This configuration allows for high redundancy and fault tolerance, as there is no central point of communication. However, it can be complex to manage because the system must ensure that all nodes agree on data changes, which can lead to conflicts and synchronization issues in larger networks.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfegx28w8oukifyhpqbc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzfegx28w8oukifyhpqbc.png" alt="Leaderless replication" width="800" height="249"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🤓 This topology is ideal for highly available, partition-tolerant systems where eventual consistency is acceptable. It is often used in systems that require horizontal scaling without a single point of failure, such as large-scale e-commerce websites or distributed data storage systems that need to handle massive traffic loads without downtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replication Strategies
&lt;/h2&gt;

&lt;p&gt;When it comes to database replication, the strategy you choose will depend on your business needs and how you want your system to function. Here are the most common replication strategies:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full Replication&lt;/strong&gt;&lt;br&gt;
In full replication, every replica of the database contains an identical copy of all data. This means that each server stores a complete version of the database, ensuring that data is always available across multiple locations. This approach is particularly useful for systems where high availability and fast access to all data are critical. It’s like having several backup copies of everything in the database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Partial Replication&lt;/strong&gt;&lt;br&gt;
Partial replication is when only a subset of the database is replicated to each server. Instead of duplicating the entire database, each replica holds only part of the data that’s needed for its specific use case. For example, one server may hold customer data, while another holds order information. This approach is more efficient when certain types of data are accessed more frequently than others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Snapshot Replication&lt;/strong&gt;&lt;br&gt;
Snapshot replication involves periodically taking a snapshot (or copy) of the database and sending it to the replicas. Rather than constantly updating the replicas in real time, the system refreshes the replica at set intervals—such as once a day or once an hour. This is useful when you don’t need constant updates, but want to ensure that all replicas are eventually up-to-date at specific times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transactional Replication&lt;/strong&gt;&lt;br&gt;
Transactional replication is a more dynamic approach where data changes (such as inserts, updates, and deletes) are continuously propagated to the replicas. This ensures that all replicas remain in sync with the leader server in near real-time. Whenever there is a change to the database, whether it's adding a new record or modifying an existing one, those changes are immediately reflected across all replicas. This is ideal for applications that require near-instant consistency across all nodes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Merge Replication&lt;/strong&gt;&lt;br&gt;
Merge replication allows multiple replicas to independently modify the data. Changes made at different nodes are later merged together to maintain consistency across all replicas. This approach is especially useful in scenarios where different users or locations need to make updates simultaneously, such as collaborative platforms or distributed systems. Once the data is merged, any conflicting changes are resolved using pre-defined rules to ensure consistency.&lt;/p&gt;

&lt;p&gt;🤓 Each replication strategy serves a different purpose, and choosing the right one depends on your system’s needs. For businesses that require high availability and low latency, full replication might be the best option. For applications with less critical real-time data needs, snapshot replication might be a more efficient choice. On the other hand, transactional replication works well for systems that require consistency and real-time synchronization. Merge replication is perfect for systems where independent data changes are common, and data needs to be synchronized later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Synchronous vs Asynchronous Replication
&lt;/h2&gt;

&lt;p&gt;In the world of database replication, one of the most important decisions revolves around timing: when should data be copied from the primary node to its replicas? This decision shapes the system’s performance, consistency, and resilience — and it boils down to two main strategies: &lt;strong&gt;synchronous&lt;/strong&gt; and &lt;strong&gt;asynchronous&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Synchronous Replication&lt;/strong&gt;&lt;br&gt;
Synchronous replication means the primary database and its replicas stay perfectly in sync at all times. Every time a user performs a write — like submitting a transaction or saving a form — that change must be successfully written not only to the primary database but also to one or more replicas before the transaction is confirmed as complete. In other words, the user has to wait until the data is safely stored in all participating databases.&lt;/p&gt;

&lt;p&gt;The main benefit of this strategy is strong consistency. You can be confident that if a node goes down, no recent transactions will be lost — all copies are up-to-date. This is essential in systems where data integrity is critical, such as banking, medical records, or inventory systems. But the cost of this safety is performance: every write is slower, and system responsiveness can suffer if any replica is slow or unreachable. In extreme cases, a single failed node might prevent new transactions from being processed at all.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fld7prjo6xe8qn8291ndw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fld7prjo6xe8qn8291ndw.png" alt="Synchronous replication" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👷🌎 &lt;strong&gt;Example&lt;/strong&gt; 🌎👷&lt;br&gt;
Online banking platforms and financial exchanges are textbook cases for synchronous replication. In these environments, even a tiny inconsistency — like a payment not registering or a trade executing twice — can result in major financial and legal consequences. Therefore, maintaining perfect synchronization is worth the performance trade-off&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Asynchronous Replication&lt;/strong&gt;&lt;br&gt;
Asynchronous replication takes a different approach: it prioritizes speed. When a user submits a write, the primary database processes and commits the change immediately, without waiting for replicas. The changes are sent to replicas afterward, in the background. This dramatically improves performance and responsiveness, making it ideal for systems with very high throughput or where users are distributed globally.&lt;/p&gt;

&lt;p&gt;However, this speed comes at the cost of eventual consistency. If the primary node crashes before all changes reach the replicas, there’s a risk of data loss. This is acceptable in use cases where perfect, real-time consistency is less important — for example, in social media apps, content platforms, or analytics dashboards, where occasional data lag isn’t a major concern.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fata4dpk5k6opr99qllgx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fata4dpk5k6opr99qllgx.png" alt="Asynchronous replication" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👷🌎 &lt;strong&gt;Example&lt;/strong&gt; 🌎👷&lt;br&gt;
Instagram’s “like” system is a great example of asynchronous replication in action. When you double-tap a photo, your like is recorded instantly, giving you fast feedback — but the update might take a second or two to appear for your friends or even disappear briefly during high load. That’s okay, because likes are non-critical data. Prioritizing speed over strict consistency enables Instagram to serve billions of actions per day efficiently without slowing the user experience&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztoetqj25zuck9kcfkw6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztoetqj25zuck9kcfkw6.jpg" alt="Sync vs Async replication" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Database Backup vs Replication
&lt;/h2&gt;

&lt;p&gt;Though often mentioned together, database backup and replication serve very different purposes in a data infrastructure. Understanding their roles can help businesses make smarter choices when designing systems for reliability, disaster recovery, and performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database Backup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Backups are periodic snapshots of your database, usually stored in a separate location from the original system. Their primary goal is &lt;strong&gt;data recovery&lt;/strong&gt; — if something catastrophic happens (like accidental data deletion, or corruption), you can restore your system to a previous, known-good state.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fycnfzvpixvldxmdltyyx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fycnfzvpixvldxmdltyyx.jpg" alt="Database Backup" width="445" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👷🌎 Backups are ideal when you need long-term recovery options or protection from human error. They’re also essential for compliance in industries where historical data must be retained, such as healthcare or finance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database Replication&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Replication, on the other hand, is about maintaining live copies of your data across multiple servers in real time or near-real time. It’s designed for &lt;strong&gt;high availability&lt;/strong&gt;, &lt;strong&gt;load balancing&lt;/strong&gt;, and &lt;strong&gt;fault tolerance&lt;/strong&gt;. If one server goes down, another replica can immediately take over with little or no downtime. Unlike backups, replication doesn’t protect against logical errors — if bad data is written to the primary database, it’s usually also written to all replicas. Replication is about system continuity, not recovery from past states.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyb0w1wprcl68cxevq5w6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyb0w1wprcl68cxevq5w6.png" alt="Database replication" width="636" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👷🌎 Replication is ideal when you need a system to stay online 24/7, or when you're serving global users and want to distribute read requests closer to them. It’s widely used in microservices, content platforms, SaaS applications, and any system requiring real-time access to data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerations and Challenges
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Helpful Links 🤓
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Text resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.qlik.com/us/data-replication/database-replication#:~:text=Database%20replication%20refers%20to%20the,system%20fault%2Dtolerance%20and%20reliability." rel="noopener noreferrer"&gt;Database Replication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rivery.io/data-learning-center/complete-guide-to-data-replication/" rel="noopener noreferrer"&gt;Complete Guide to Database Replication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fivetran.com/learn/database-replication" rel="noopener noreferrer"&gt;Database replication: Definition, types and setup&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Video resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=jLEp1XI_L6Q" rel="noopener noreferrer"&gt;Database Replication &amp;amp; Sharding Explained&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=bI8Ry6GhMSE" rel="noopener noreferrer"&gt;Database Replication Explained (in 5 Minutes)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=aE2UPg3Ckck" rel="noopener noreferrer"&gt;All Types of Database Replication Discussed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=WG6k74VSOOU" rel="noopener noreferrer"&gt;Database Replication Explained | System Design Interview Basics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>backenddevelopment</category>
      <category>webdev</category>
      <category>database</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Databases: SQL vs NoSQL</title>
      <dc:creator>Nikita Kutsokon</dc:creator>
      <pubDate>Fri, 21 Mar 2025 11:42:06 +0000</pubDate>
      <link>https://dev.to/nikita_kutsokon/databases-sql-vs-nosql-4f1j</link>
      <guid>https://dev.to/nikita_kutsokon/databases-sql-vs-nosql-4f1j</guid>
      <description>&lt;h2&gt;
  
  
  What is SQL ?
&lt;/h2&gt;

&lt;p&gt;SQL (Structured Query Language) - is a specialized language designed for managing and manipulating databases. It enables users to efficiently store, retrieve, update, and delete structured data within relational databases. &lt;/p&gt;

&lt;p&gt;A relational database is a type of database that organizes data into tables (relations) consisting of rows and columns. Each table has a predefined schema, ensuring data consistency and relationships between different tables. These relationships are established using primary keys and foreign keys, allowing efficient data retrieval and integrity. Let's look at some examples of SQL code along with their purpose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetches all users from the table
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Updates the email of the user with ID = 1
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;Users&lt;/span&gt; 
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'john.doe@example.com'&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Deletes the user with ID = 1
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Users&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What is NoSQL ?
&lt;/h2&gt;

&lt;p&gt;NoSQL (Not Only SQL) is a type of database designed for storing and managing large volumes of unstructured, semi-structured, or rapidly changing data. Unlike traditional relational databases, NoSQL databases do not rely on fixed schemas or tables with rows and columns. Instead, they allow for more flexible data models that can accommodate a variety of data types such as documents, key-value pairs, graphs, and wide-column stores.&lt;/p&gt;

&lt;p&gt;NoSQL databases are often used in applications that require high performance, scalability, and the ability to handle big data or rapidly changing data. Here are a few examples of NoSQL code and their purposes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Insert a document into a Users collection
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;john@example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;age&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;address&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;street&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;123 Elm St.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;city&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Springfield&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;zip&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;12345&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Find all movies liked by John Doe's friends
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nc"&gt;MATCH &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;john&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nx"&gt;FRIEND&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;friend&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nx"&gt;LIKES&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;RETURN&lt;/span&gt; &lt;span class="nx"&gt;friend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Retrieving all items from the cart
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;LRANGE&lt;/span&gt; &lt;span class="nx"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1001&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pros and Cons of SQL Databases
&lt;/h2&gt;

&lt;p&gt;SQL databases are widely used for storing and managing structured data in a relational model, where data is organized into tables with predefined schemas. They are known for strong consistency, reliability, and complex querying capabilities, making them ideal for applications that require data integrity and structured relationships. However, while SQL databases offer many advantages, they also have limitations, especially when dealing with scalability and unstructured data. Below is a breakdown of the key pros and cons of SQL databases to help determine when they are the right choice: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅ Pros&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structured Data &amp;amp; Schema Enforcement&lt;/strong&gt;&lt;br&gt;
SQL databases follow a strict schema, ensuring organized and consistent data storage. This makes them well-suited for applications requiring well-defined relationships between data entities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ACID Compliance&lt;/strong&gt;&lt;br&gt;
SQL databases adhere to Atomicity, Consistency, Isolation, and Durability principles, ensuring data accuracy, reliability, and integrity, which is critical for financial and transactional applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Powerful Querying Capabilities&lt;/strong&gt;&lt;br&gt;
SQL provides advanced querying features such as JOIN, aggregations, and indexing, allowing users to retrieve complex data efficiently from multiple tables.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Standardization &amp;amp; Wide Adoption *&lt;/em&gt;&lt;br&gt;
SQL is a universally recognized language with extensive documentation, making it easy for developers to learn and work with across various database management systems like MySQL, PostgreSQL, SQL Server, and Oracle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;❌ Cons&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scalability Limitations&lt;/strong&gt; &lt;br&gt;
SQL databases typically scale vertically by adding more resources (CPU, RAM, storage) to a single server. However, due to their relational nature, they struggle with horizontal scaling, which involves distributing data across multiple servers. This limitation can create bottlenecks when dealing with high traffic or large datasets, making it difficult to efficiently scale out in distributed environments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fixed Schema&lt;/strong&gt;&lt;br&gt;
Changing the schema (adding or modifying columns) often requires migrations, which can be time-consuming and impact application performance. This makes SQL databases less adaptable to rapidly evolving data structures.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;High Licensing Costs for Enterprise Solutions *&lt;/em&gt;&lt;br&gt;
While open-source options like MySQL and PostgreSQL are free, commercial SQL databases such as Oracle and Microsoft SQL Server can have high licensing costs, making them expensive for large-scale deployments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pros and Cons of NoSQL Databases
&lt;/h2&gt;

&lt;p&gt;NoSQL databases are designed to handle large volumes of unstructured, semi-structured, and structured data with a focus on scalability, flexibility, and high-speed performance. Unlike SQL databases, NoSQL does not enforce a strict schema, making it an excellent choice for big data, real-time applications, and distributed systems. While NoSQL databases offer significant advantages in terms of performance and scalability, they also have drawbacks, particularly in areas like data consistency and complex querying. Below is a breakdown of the key pros and cons of NoSQL databases to help determine when they are the right choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅ Pros&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flexible Schema &amp;amp; Dynamic Data Models&lt;/strong&gt; &lt;br&gt;
NoSQL databases do not require a predefined schema, allowing for rapid changes in data structure without complex migrations. This is ideal for applications where data formats evolve over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;High Scalability&lt;/strong&gt;&lt;br&gt;
NoSQL databases scale horizontally by distributing data across multiple servers, making them well-suited for handling massive amounts of data and high traffic loads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;High Availability &amp;amp; Fault Tolerance&lt;/strong&gt;&lt;br&gt;
Many NoSQL databases use replication and sharding to ensure high availability and resilience, making them ideal for distributed and cloud-native applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Faster Write Operations&lt;/strong&gt;&lt;br&gt;
Unlike traditional SQL databases that enforce strict consistency, NoSQL databases often prioritize speed over consistency, making them much faster for write-heavy workloads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;❌ Cons&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eventual Consistency (BASE Model)&lt;/strong&gt;&lt;br&gt;
Unlike SQL databases, which follow ACID properties, most NoSQL databases follow the BASE model. This can lead to temporary inconsistencies, which may not be acceptable for applications requiring strong data integrity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steeper Learning Curve &amp;amp; Maintenance Challenges&lt;/strong&gt;&lt;br&gt;
While SQL is a standardized language, NoSQL databases vary significantly in design (e.g., MongoDB, Cassandra, Redis, Neo4j), requiring specialized knowledge to manage and optimize performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not Ideal for Transactions&lt;/strong&gt;&lt;br&gt;
NoSQL databases are not the best choice for applications that require multi-row transactions, as they often lack full ACID compliance, leading to potential issues with data consistency and rollback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Differences Between SQL and NoSQL
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Data Structure&lt;/strong&gt;&lt;br&gt;
SQL databases use a relational model, where data is stored in structured tables with predefined schemas consisting of rows and columns. This structure enforces a strict organization, ensuring that data adheres to a set pattern. This makes SQL ideal for applications that require complex queries and strong consistency in structured data, such as financial systems. In contrast, NoSQL databases offer a more flexible approach, using a variety of data models such as key-value pairs, documents, graphs, and column families. This flexibility allows NoSQL to handle unstructured or semi-structured data, making it suitable for applications that need dynamic schemas and easy adaptation to changes in data over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;&lt;br&gt;
SQL databases typically scale vertically, meaning they add more resources (like CPU, RAM, or storage) to a single server to handle increased load. However, due to their relational nature, SQL databases face challenges with horizontal scaling, where data is distributed across multiple servers. This makes scaling more complex and resource-intensive as the amount of data and user requests increase. On the other hand, NoSQL databases are designed for horizontal scaling, which allows them to easily distribute data across multiple servers, enabling them to handle high volumes of data and traffic more efficiently. This scalability makes NoSQL an ideal choice for applications with large-scale, distributed data needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;br&gt;
SQL databases offer solid performance for read-heavy workloads, where data is relatively stable, and complex queries with multiple joins are necessary. However, SQL databases can experience performance issues under heavy write operations due to their need to maintain strong consistency across the system. This can lead to slower query performance as the database grows. NoSQL databases, however, are optimized for high-speed writes. With their flexible data models and ability to distribute data, NoSQL databases can process large amounts of data quickly, making them ideal for applications that require fast access to large datasets, such as real-time analytics or social media platforms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consistency vs Availability (&lt;a href="https://dev.to/nikita_kutsokon/databases-sql-vs-nosql-3d4f-temp-slug-5673266"&gt;ACID vs BASE&lt;/a&gt;)&lt;/strong&gt;&lt;br&gt;
SQL databases follow the ACID model, which ensures that database transactions are processed reliably and maintain strong consistency. This makes them ideal for applications where data integrity and reliability are crucial, such as banking systems. However, this strict consistency can limit the system’s ability to scale easily or recover from failures. NoSQL databases typically follow the BASE model, prioritizing availability and partition tolerance over immediate consistency. This means that while data may not be consistent immediately, NoSQL systems are designed to remain operational and available, making them suitable for applications where uptime and performance are more critical than absolute consistency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Storage and Data Integrity&lt;/strong&gt;&lt;br&gt;
SQL databases provide robust storage and data integrity features, ensuring that the data remains consistent and accurate across transactions. With built-in mechanisms like foreign keys and constraints, SQL databases ensure that data relationships are maintained and that data integrity is not compromised. However, this can be limiting when dealing with rapidly changing or vast amounts of data. NoSQL databases, while generally providing less rigid data integrity guarantees, offer flexibility by allowing data to be stored in various formats and distributed across multiple nodes. This design ensures high availability and fault tolerance, but can sometimes result in eventual consistency, where data across nodes may not be immediately synchronized. This trade-off is often acceptable in scenarios that prioritize scalability and speed over strict consistency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Types of SQL and NoSQL Databases
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fea4gtdwd4h5qi4phkobz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fea4gtdwd4h5qi4phkobz.jpg" alt="Most popular RDBMS" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re looking at SQL databases, there are several popular options, each with its own strengths. For instance, &lt;strong&gt;MySQL&lt;/strong&gt; is widely used in web applications due to its reliability, scalability, and ease of use. Then, there’s &lt;strong&gt;PostgreSQL&lt;/strong&gt;, which is great for handling large datasets and complex data structures, thanks to its support for complex queries, joins, and ACID compliance. If you’re working in an enterprise environment, &lt;strong&gt;Microsoft SQL Server&lt;/strong&gt; is often the go-to choice, offering high security and seamless integration with other Microsoft products. For larger, more advanced needs, &lt;strong&gt;Oracle Database&lt;/strong&gt; shines with its robustness, scalability, and features like clustering and partitioning. Lastly, if you need something lightweight for smaller-scale applications or embedded systems, &lt;strong&gt;SQLite&lt;/strong&gt; is a great choice, being file-based and easy to integrate directly into applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffsl59fv8pddbr0jnjtsy.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffsl59fv8pddbr0jnjtsy.jpeg" alt="Types of NoSQL DBMS" width="645" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;NoSQL databases come in different types, each suited for specific use cases. Key-Value Stores are the simplest, storing data as key-value pairs, making them fast and ideal for caching and quick retrieval. Examples of this type include &lt;strong&gt;Redis&lt;/strong&gt; and &lt;strong&gt;Riak&lt;/strong&gt;. Document Stores store data as documents, typically in formats like JSON, BSON, or XML, making them well-suited for semi-structured data. Popular examples are &lt;strong&gt;MongoDB&lt;/strong&gt; and &lt;strong&gt;CouchDB&lt;/strong&gt;. Column-Family Stores organize data in columns instead of rows, which is great for fast read and write operations on large datasets. &lt;strong&gt;Apache Cassandra&lt;/strong&gt; and &lt;strong&gt;HBase&lt;/strong&gt; are key examples here. Graph Databases focus on relationships between data points, storing data as nodes and edges, making them perfect for applications like social networks or recommendation systems. &lt;strong&gt;Neo4j&lt;/strong&gt; and &lt;strong&gt;ArangoDB&lt;/strong&gt; are prominent graph databases. Lastly, Time-Series Databases are optimized for handling time-ordered data, such as logs or sensor readings. &lt;strong&gt;InfluxDB&lt;/strong&gt; and &lt;strong&gt;TimescaleDB&lt;/strong&gt; are examples used for such tasks. Each type of NoSQL database is designed with a specific strength in mind, catering to the needs of different data models and applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Choose Between SQL and NoSQL
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;When to Choose SQL&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your data is structured&lt;/li&gt;
&lt;li&gt;You need ACID compliance&lt;/li&gt;
&lt;li&gt;Your queries are complex&lt;/li&gt;
&lt;li&gt;Data relationships are crucial&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;When to Choose NoSQL&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your data is semi-structured or unstructured&lt;/li&gt;
&lt;li&gt;You need high scalability&lt;/li&gt;
&lt;li&gt;Performance in writes is critical&lt;/li&gt;
&lt;li&gt;Your application prioritizes availability&lt;/li&gt;
&lt;li&gt;You handle large-scale, dynamic data&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Choosing between SQL and NoSQL depends on your application's needs. SQL is ideal for applications that require structured data, complex queries, and high consistency, such as banking systems, customer relationship management (CRM) tools, and enterprise resource planning (ERP) systems, where transactions need to be reliable and data relationships are crucial. NoSQL, on the other hand, is perfect for large-scale applications with unstructured or semi-structured data, like social media platforms, real-time analytics, content management systems, e-commerce websites, and IoT applications, where high scalability, flexibility, and quick data retrieval are essential. NoSQL databases like MongoDB, Cassandra, and Couchbase excel in handling large volumes of data across distributed systems, making them ideal for applications that need to handle massive amounts of unstructured data, real-time updates, and horizontal scalability. In some cases, combining both SQL and NoSQL databases in a hybrid approach can deliver the best of both worlds, as seen in modern web applications and cloud-based platforms where specific use cases demand the strengths of each.&lt;/p&gt;

&lt;h2&gt;
  
  
  Helpful Links 🤓
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Text resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.geeksforgeeks.org/difference-between-sql-and-nosql/" rel="noopener noreferrer"&gt;Difference between SQL and NoSQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/resources/basics/databases/nosql-explained/nosql-vs-sql" rel="noopener noreferrer"&gt;Understanding SQL vs NoSQL Databases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.coursera.org/articles/nosql-vs-sql" rel="noopener noreferrer"&gt;SQL vs. NoSQL: The Differences Explained + When to Use Each&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Video resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=_Ss42Vb1SU4" rel="noopener noreferrer"&gt;SQL vs. NoSQL Explained (in 4 Minutes)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Q5aTUc7c4jg" rel="noopener noreferrer"&gt;SQL vs. NoSQL: What's the difference?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=YDR3D2bsv9Y" rel="noopener noreferrer"&gt;Why does NoSQL exist? (MongoDB, Cassandra) | System Design&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=YgTLqO54UOA" rel="noopener noreferrer"&gt;SQL vs NoSQL - Who Wins? | Systems Design Interview 0 to 1 with Ex-Google SWE&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>database</category>
      <category>backend</category>
      <category>systemdesign</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Databases: Indexes. Part 2</title>
      <dc:creator>Nikita Kutsokon</dc:creator>
      <pubDate>Fri, 07 Mar 2025 18:10:31 +0000</pubDate>
      <link>https://dev.to/nikita_kutsokon/databases-indexes-part-2-32j7</link>
      <guid>https://dev.to/nikita_kutsokon/databases-indexes-part-2-32j7</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/nikita_kutsokon/databases-indexes-part-1-3579"&gt;previous section&lt;/a&gt;, we explored the fundamental concepts of database indexes and their role in enhancing query performance. Now, we will delve deeper into advanced indexing techniques that can further optimize your database. As data grows and queries become more complex, understanding how to fine-tune and select the right indexing strategy becomes crucial. In this section, we’ll cover different types of indexes, such as clustered, non-clustered, and composite indexes, and explore when and how to use them effectively. We will also discuss common indexing pitfalls and best practices to ensure your database remains efficient as it scales.&lt;/p&gt;




&lt;h2&gt;
  
  
  Types of Indexes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Single-Column Indexes&lt;/strong&gt;&lt;br&gt;
This is the most basic type of index. It is created on a single column of a table.&lt;/p&gt;

&lt;p&gt;Let’s say we have a users table with columns &lt;em&gt;id&lt;/em&gt;, &lt;em&gt;name&lt;/em&gt;, and &lt;em&gt;age&lt;/em&gt;. If we frequently search for users by their name, we could create an index on the name column:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE INDEX idx_name ON users(name);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This index will speed up searches like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM users WHERE name = 'Alice';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without the index, the database would have to scan every row, which is slow for large tables. But with the index, it can directly look up rows where the name is 'Alice'.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Composite Indexes&lt;/strong&gt;&lt;br&gt;
A composite index is an index that involves more than one column. It’s useful when you frequently query the database using multiple columns together in the WHERE clause or as part of JOIN conditions.&lt;/p&gt;

&lt;p&gt;Imagine we have a users table with the following columns: &lt;em&gt;first_name&lt;/em&gt;, &lt;em&gt;last_name&lt;/em&gt;, &lt;em&gt;age&lt;/em&gt;. If we often search for users by both first_name and last_name together, we can create a composite index like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE INDEX idx_name_age ON users(first_name, last_name);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if we run a query like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM users WHERE first_name = 'John' AND last_name = 'Doe';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The database will use the composite index to quickly find rows where both first_name is 'John' and last_name is 'Doe', without scanning the entire table.&lt;/p&gt;

&lt;p&gt;⚠️ Important Note:&lt;/p&gt;

&lt;p&gt;A composite index is like a combined shortcut that helps the database find information faster when searching through multiple columns at once. The order of columns in this index is important. For example, if the index is created with &lt;em&gt;first_name&lt;/em&gt; first and &lt;em&gt;last_name&lt;/em&gt; second, it works best when you search using both &lt;em&gt;first_name&lt;/em&gt; and &lt;em&gt;last_name&lt;/em&gt;. However, if you only search by &lt;em&gt;last_name&lt;/em&gt;, the index won't be as effective because it was designed to prioritize the first column (&lt;em&gt;first_name&lt;/em&gt;). In short, the database can use the index for queries that match the first column or more, but not just the later ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Unique Indexes&lt;/strong&gt;&lt;br&gt;
A unique index is an index that ensures the uniqueness of the values in the indexed column. It is automatically created when you define a column with a UNIQUE constraint.&lt;/p&gt;

&lt;p&gt;Suppose we have a users table with an email column, and we want to ensure no two users have the same email. We can create a unique index like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE UNIQUE INDEX idx_email ON users(email);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that every email in the email column is unique. If someone tries to insert a duplicate email, the database will reject the insertion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Full-Text Indexes&lt;/strong&gt;&lt;br&gt;
A full-text index is specialized for text searching. It allows the database to efficiently search for words or phrases within large text columns, often used in fields like articles, descriptions, and comments.&lt;/p&gt;

&lt;p&gt;If you have a posts table with a content column, you can create a full-text index for efficient searching:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE FULLTEXT INDEX idx_content ON posts(content);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you can perform a search like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM posts WHERE MATCH(content) AGAINST ('keyword');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is much faster than a basic search because the full-text index is designed specifically to handle such queries efficiently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Clustered Index&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A clustered index determines the physical order of data in the table. When you create a primary key on a table, a clustered index is automatically created. There can be only one clustered index per table because the data rows are physically sorted by it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(100),
    age INT
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The database will create a clustered index on the id column by default. The data in the table will be physically stored in order of id. This makes range queries like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM users WHERE id BETWEEN 1 AND 10;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. Non-Clustered Index&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A non-clustered index is a separate structure from the data table. It contains a copy of the indexed columns and a pointer to the actual rows in the table. Unlike clustered indexes, non-clustered indexes don't change the physical order of the data.&lt;/p&gt;

&lt;p&gt;For a table with a non-clustered index:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE INDEX idx_name ON users(name);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This index will help quickly look up rows based on the name column, but the data in the table remains unordered based on name.&lt;/p&gt;




&lt;h2&gt;
  
  
  Table Scans
&lt;/h2&gt;

&lt;p&gt;When querying a database, the way the system retrieves data from tables significantly affects performance. Databases use different scanning methods to fetch records, depending on whether indexes are available and how the query is structured. Understanding these table scans helps in optimizing queries and designing efficient indexes. Let's look at some of them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Sequential Table Scan&lt;/strong&gt;&lt;br&gt;
A Sequential Table Scan occurs when the database reads every row in a table to find matching records. This happens when:&lt;/p&gt;

&lt;p&gt;No index exists on the column being queried. The query optimizer determines that scanning the entire table is more efficient than using an index&lt;br&gt;
Suppose we have a users table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM users WHERE age = 25;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If age is not indexed, the database will check each row, making this slow for large tables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Index Scan&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An Index Scan occurs when the database reads the entire index instead of scanning the table directly. This is more efficient than a full table scan but can still lead to high I/O costs for large datasets because, after scanning the index, the database needs to fetch the actual data from the table. This is more efficient than a full table scan but still involves scanning multiple entries in the index.&lt;/p&gt;

&lt;p&gt;If age is indexed, the query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM users WHERE age = 25;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will first scan the index for matching values before retrieving actual records. This is faster than a sequential scan but can still be expensive if many rows match.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Bitmap Index Scan&lt;/strong&gt;&lt;br&gt;
A Bitmap Index Scan works differently from a traditional index scan because it is optimized for columns with low cardinality (few unique values). Instead of storing direct row pointers, it uses a bitmap (a series of bits) to represent which rows contain a particular value.&lt;/p&gt;

&lt;p&gt;Let's say we have a users table with a status column that can have only three values: active, inactive, and banned. Since there are only three possible values, this column is a great candidate for a bitmap index.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How It Works&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine we have a users table with 10 million rows and a status column, which can have only three values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;active&lt;/li&gt;
&lt;li&gt;inactive&lt;/li&gt;
&lt;li&gt;banned&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we don’t use an index, searching for all active users would mean checking each row one by one, which is slow. Instead the database creates a separate bitmap for each unique value (active, inactive, banned). Each bitmap is simply a long list of 1 and 0, where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 means the row has that value.&lt;/li&gt;
&lt;li&gt;0 means the row does not have that value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmm8cdms4ce7tk5efxpl8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmm8cdms4ce7tk5efxpl8.png" alt="Bitmap indexing" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, if we run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM users WHERE status = 'active';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of scanning the whole table, the database retrieves the bitmap for 'active':&lt;/p&gt;

&lt;p&gt;&lt;code&gt;1 0 1 0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This tells the database exactly which rows contain active (1st, 3rd). The system skips all rows where the bit is 0, making the lookup very fast. Finally, it fetches only those rows from the actual table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Is This Efficient ?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bitmaps are small&lt;/strong&gt; → They use less space compared to traditional indexes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast Filtering&lt;/strong&gt; → The database can quickly determine matching rows using bitwise operations (AND, OR).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Great for Multiple Conditions&lt;/strong&gt; → If we add another condition, like:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM users WHERE status = 'active' AND age = 30;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The database just combines bitmaps for status = 'active' and age = 30 using a bitwise AND operation, avoiding unnecessary scans.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to Use a Bitmap Index&lt;/strong&gt;&lt;br&gt;
✔ Best for columns with few unique values (status, gender, category).&lt;br&gt;
❌ Not efficient for high-cardinality columns (username, email).&lt;/p&gt;


&lt;h2&gt;
  
  
  Understanding the EXPLAIN Query
&lt;/h2&gt;

&lt;p&gt;The EXPLAIN command in PostgreSQL provides the query execution plan that shows how the database will execute your query. This helps to analyze and optimize the performance of queries. Let's break down each part of the provided SQL and EXPLAIN results. To see how it is works, lets create a &lt;em&gt;customer&lt;/em&gt; table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE customer (
    id SERIAL PRIMARY KEY,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL,
    status VARCHAR(10) CHECK (status IN ('active', 'inactive', 'banned')) NOT NULL,
    age INT CHECK (age &amp;gt;= 0)
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a customer table with columns for &lt;em&gt;id&lt;/em&gt;, &lt;em&gt;first_name&lt;/em&gt;, &lt;em&gt;last_name&lt;/em&gt;, &lt;em&gt;status&lt;/em&gt;, and &lt;em&gt;age&lt;/em&gt;. To play with this table we need data in it, lets insert random with the next query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSERT INTO customer (first_name, last_name, status, age)
SELECT 
    LEFT(md5(random()::text), 10),
    LEFT(md5(random()::text), 10),
    (ARRAY['active', 'inactive', 'banned'])[floor(random() * 3 + 1)], 
    floor(random() * 80 + 18)
FROM generate_series(1, 10);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have a table with next data: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dm6f2ypucyjf586o66k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dm6f2ypucyjf586o66k.png" alt="customer table overview" width="712" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's see how the EXPLAIN query works in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EXPLAIN SELECT * FROM customer;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn29wepguzwfya402nas5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn29wepguzwfya402nas5.png" alt="Explain query" width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This command shows the execution plan for selecting all rows from the customer table. It will likely use a Seq Scan (sequential scan) because no index is defined yet, and the entire table is being scanned. Let's extend our abilities of EXPLAIN with ANALYZE parameter. &lt;strong&gt;EXPLAIN ANALYZE&lt;/strong&gt; executes the query and returns both the execution plan and the actual runtime statistics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EXPLAIN ANALYZE  SELECT * FROM customer WHERE status = 'banned';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqkzgsiu16qkefl9logqy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqkzgsiu16qkefl9logqy.png" alt="explain analyze" width="800" height="139"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's break down the EXPLAIN ANALYZE output for the query:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Seq Scan on customer&lt;/strong&gt;&lt;br&gt;
The query starts with a sequential scan (Seq Scan) on the customer table. This means PostgreSQL is checking each row of the table to find the records that match the condition (status = 'banned'). Since no index is set up for the status column, PostgreSQL has no shortcut to directly find the rows it needs. Instead, it has to look through the entire table, one row at a time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;cost=0.00..13.25 rows=1 width=282&lt;/strong&gt;&lt;br&gt;
The cost of executing this query is estimated at 13.25, with 0.00 as the startup cost and 13.25 as the total cost. The startup cost is low because PostgreSQL only needs minimal resources to start executing the query. The total cost is higher because PostgreSQL needs to go through all the rows to apply the filter (status = 'banned'). The value 13.25 represents the internal calculation PostgreSQL uses to estimate how much work it will take to process the query. It also expects that about 1 row will match the condition.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;rows=1&lt;/strong&gt;&lt;br&gt;
PostgreSQL's initial estimation of the number of rows that will match the condition (status = 'banned'). This is an estimate based on table statistics.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;width=282&lt;/strong&gt;&lt;br&gt;
The average size (in bytes) of the rows in the customer table.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;actual time 0.147..0.151&lt;/strong&gt;&lt;br&gt;
In terms of actual execution, the query took around 0.147 to 0.151 milliseconds to complete. This is how long PostgreSQL took to scan the table and find the rows that matched the condition. Since only 5 rows matched the condition, it was able to process the query very quickly, with the total time of only 0.151 ms.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;rows=5 loops=1&lt;/strong&gt;&lt;br&gt;
Finally, the query executed in a single loop (loops=1). This means PostgreSQL only had to scan the table once to find the matching rows. Even though it estimated that only 1 row would be returned, it actually found 5 rows that had the status 'banned', which is why 5 rows were returned. This reflects the actual results of the query.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;To illustrate how adding an index can change the table scan type, let's walk through the process with the customer table:&lt;/p&gt;

&lt;p&gt;We start by inserting a huge amount of random data into the customer table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INSERT INTO customer (first_name, last_name, status, age)
SELECT 
    LEFT(md5(random()::text), 10),
    LEFT(md5(random()::text), 10),
    (ARRAY['active', 'inactive', 'banned'])[floor(random() * 3 + 1)], 
    floor(random() * 80 + 18)
FROM generate_series(1, 1000000);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsu8dnf8vh1d5qzyl7n3e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsu8dnf8vh1d5qzyl7n3e.png" alt="More data for customer table" width="750" height="834"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's check the query plan for selecting rows based on the &lt;em&gt;first_name&lt;/em&gt; column:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EXPLAIN ANALYZE  SELECT * FROM customer WHERE first_name  = '698ffdfe4d';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The database decides to use a Sequential Scan (Seq Scan), meaning it scans all rows in the table to find the matching entry. Additionally, parallel workers are used to improve the scan efficiency when dealing with larger datasets:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0wgmxd4qqi6vakuanhba.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0wgmxd4qqi6vakuanhba.png" alt="seq scan" width="800" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we add an index on the first_name column to improve search performance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE INDEX idx_customer_first_name ON customer(first_name);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the index is created, let's run the same query again to see the changes in the execution plan:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EXPLAIN ANALYZE  SELECT * FROM customer WHERE first_name  = '698ffdfe4d';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see, after adding the index, the database now uses an Index Scan rather than a Sequential Scan. This significantly reduces the query execution time and cost.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdl2s76yxbq6cawiiamtb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdl2s76yxbq6cawiiamtb.png" alt="Image description" width="800" height="96"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎉 The Index Scan using _id_customer_first_name is approximately 263 times faster than the Sequential Scan (0.233 ms vs 61.311 ms). This demonstrates the significant performance boost indexing provides, especially when filtering by a specific column in large datasets. By avoiding a full table scan, the index dramatically reduces query execution time and improves efficiency.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Choose the Right Index
&lt;/h2&gt;

&lt;p&gt;Choosing the right index for a table is critical to optimizing query performance. While indexes can significantly speed up read operations, they come with overhead on write operations (like INSERT, UPDATE, DELETE) because the indexes need to be maintained. Therefore, it’s essential to strike a balance between the speed of queries and the cost of maintaining indexes. Here are some guidelines to help you choose the best index for your scenario:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understand Your Queries&lt;/strong&gt;&lt;br&gt;
Before creating an index, analyze which queries run most often. Focus on columns in WHERE, JOIN, and ORDER BY clauses, as indexing them can speed up search and sorting operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose High-Selectivity Columns&lt;/strong&gt;&lt;br&gt;
Indexes work best on columns with many unique values, like email or user_id. Columns with few values (status or gender) may not benefit much from a regular index, but bitmap indexes can be useful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single vs Composite Indexes&lt;/strong&gt;&lt;br&gt;
A single-column index is best for filtering by one column, while a composite index is better for queries using multiple columns together. Remember, in composite indexes, the order of columns matters—queries should use the left-most column first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Balance Indexes with Write Performance&lt;/strong&gt;&lt;br&gt;
Indexes speed up searches but slow down writes (INSERT, UPDATE, DELETE) because they need to be updated too. Avoid unnecessary indexes and regularly check for unused ones to maintain fast performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consider Table Size&lt;/strong&gt;&lt;br&gt;
For small tables, indexes might not make a big difference. But for large tables, they are essential to avoid slow full-table scans. Sparse data (many NULL values) can also reduce index efficiency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test and Optimize&lt;/strong&gt;&lt;br&gt;
Use tools like EXPLAIN to check how your queries use indexes. Try different index types and compare performance to find the best option. Regularly update your indexing strategy as your data and queries evolve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Helpful Links 🤓
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Text resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://thoughtbot.com/blog/reading-an-explain-analyze-query-plan" rel="noopener noreferrer"&gt;Reading a Postgres EXPLAIN ANALYZE Query Plan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://patrickkarsh.medium.com/choosing-the-right-index-database-design-basics-e797cb49a7c8" rel="noopener noreferrer"&gt;Choosing the Right Index: Database Design Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vertabelo.com/blog/database-index-types/" rel="noopener noreferrer"&gt;What Are the Types of Indexes in a Relational Database?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Video resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=BxAj3bl00-o&amp;amp;list=WL&amp;amp;index=12" rel="noopener noreferrer"&gt;SQL Indexes | Clustered vs. Nonclustered Index&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=31EmOKBP1PY" rel="noopener noreferrer"&gt;A beginners guide to EXPLAIN ANALYZE – Michael Christofides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=EZ3jBam2IEA" rel="noopener noreferrer"&gt;Database Design 39 - Indexes (Clustered, Nonclustered, Composite Index)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>database</category>
      <category>systemdesign</category>
      <category>webdev</category>
      <category>backend</category>
    </item>
    <item>
      <title>Databases: Indexes. Part 1</title>
      <dc:creator>Nikita Kutsokon</dc:creator>
      <pubDate>Tue, 04 Mar 2025 20:05:37 +0000</pubDate>
      <link>https://dev.to/nikita_kutsokon/databases-indexes-part-1-3579</link>
      <guid>https://dev.to/nikita_kutsokon/databases-indexes-part-1-3579</guid>
      <description>&lt;p&gt;This article will introduce you to the concept of database indexes. Before diving into indexes, it’s recommended to first read about &lt;a href="https://dev.to/nikita_kutsokon/databases-how-data-is-stored-on-disk-22k8"&gt;&lt;strong&gt;how databases store data&lt;/strong&gt;&lt;/a&gt;, as this will provide a better understanding of how indexes fit into the overall database architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is An Index In a Database?
&lt;/h2&gt;

&lt;p&gt;An index in a database is like the table of contents in a book. It helps the database find information faster, just like a table of contents helps you quickly find a chapter in a book. Normally, when you search for something in a database, it has to scan every row in a table, which takes time. An index is a special structure that keeps track of where data is stored, allowing the database to find it quickly. It works similarly to a library catalog, which helps locate books without checking every shelf, making searches more efficient.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhup09lvc3vpewkt8mxut.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhup09lvc3vpewkt8mxut.jpg" alt="library-catalog" width="640" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Are Indexes Important ?
&lt;/h2&gt;

&lt;p&gt;In database management, indexes are very helpful tools. They make it easier and faster to find and retrieve specific information. Here are some key benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Faster Data Retrieval&lt;/strong&gt; - when searching for a specific record, an index allows the database to find the result directly, instead of scanning every row. This significantly reduces query time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficient Sorting and Filtering&lt;/strong&gt; - queries with ORDER BY or WHERE conditions run much faster because the database can use the index instead of sorting or filtering all rows manually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Performance for Large Databases&lt;/strong&gt; - as data increases, queries can slow down. Indexes help keep search times consistent, even when dealing with millions of records.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimized Joins Between Tables&lt;/strong&gt; - indexes speed up JOIN operations by quickly matching related records between tables, making complex queries more efficient.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These benefits make indexes essential for maintaining the performance and efficiency of databases, especially as they grow larger.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Indexes Are Stored in a Database
&lt;/h2&gt;

&lt;p&gt;Indexes are stored separately from the main table data. They act as a separate data structure that is linked to the table. An index typically stores a reference to the row in the table and the indexed column's value. Most relational databases use B-trees (Balanced Trees) or hash tables for storing indexes. The structure allows efficient lookups, insertions, and deletions. Here's how it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;B-trees (or B+ trees):&lt;/strong&gt; These are the most common data structures used for indexing. The tree structure allows the database to maintain sorted values, and the search can quickly navigate the tree in a logarithmic manner, making the lookup faster. The leaf nodes of the tree contain the actual data pointers, allowing for efficient retrieval.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hash Indexes:&lt;/strong&gt; A hash table uses a hash function to convert the indexed column's value into a fixed-size hash code, which then points to the data rows. This is efficient when dealing with equality searches (WHERE column = value), but it doesn’t support range queries (WHERE column &amp;gt; value).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17zpf554db3nlw13nips.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17zpf554db3nlw13nips.jpg" alt="db-index" width="800" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Indexes Are Fast
&lt;/h2&gt;

&lt;p&gt;The reason why an index speeds up searches in databases is the use of &lt;strong&gt;binary search&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Without an index, if you wanted to search for a specific value in a large table, the database would have to scan every row to find the match. This process is known as a full table scan, and it has a time complexity of O(n), where n is the number of rows. With an index, the database doesn’t need to scan every row. It can use binary search to locate the desired data much faster. Binary search works by dividing the data in half repeatedly, narrowing down the search space quickly. Instead of checking every single record, it cuts the search space in half with each step.&lt;/p&gt;

&lt;p&gt;For example, in a sorted list, a binary search can locate an element in O(log n) time, where n is the number of items. The larger the data set, the more significant the performance improvement when using an index.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Big O Notation Comparison&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Full Table Scan (No Index): O(n)&lt;/strong&gt;&lt;br&gt;
Every record is checked one by one. Time increases linearly with the number of records.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Indexed Search (Using Binary Search): O(log n)&lt;/strong&gt;&lt;br&gt;
The number of checks decreases exponentially with each step. Even for large datasets, the number of operations remains much lower than a full table scan.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdn4y64zydiqjogcen23d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdn4y64zydiqjogcen23d.png" alt="Big O Notation Comparison" width="800" height="691"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see from the graph, the time complexity for a full table scan increases linearly (O(n)) with the size of the dataset, while the time complexity for an indexed search using binary search increases logarithmically (O(log n)).&lt;/p&gt;

&lt;h2&gt;
  
  
  How Indexes Help with Search in a Library
&lt;/h2&gt;

&lt;p&gt;Imagine you’re in a large library trying to find a specific book. The library has thousands of books, and you’re looking for a book titled “The Art of Programming”. Here’s how an index would help speed up the search:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without an Index&lt;/strong&gt;&lt;br&gt;
If the books are randomly arranged on shelves, you’d have to check each book one by one to find the one you’re looking for. This is similar to performing a full table scan. The librarian would start at the first book and keep checking each title until they find “The Art of Programming”. If there are 100,000 books, you might have to check a lot of them before finding your desired book.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Time Complexity:&lt;/strong&gt; O(n) (You might have to check all the books, linearly).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With an Index&lt;/strong&gt;&lt;br&gt;
Now imagine the library has a catalog that lists all books alphabetically. The catalog helps you directly jump to the section where books starting with "A" are located. So, instead of scanning the whole library, you can use the catalog to quickly locate where the book should be and directly go to that section. In a database, indexes work the same way. They allow the database to directly jump to the section of the data where the relevant records are located, rather than scanning through the entire table.&lt;/p&gt;

&lt;p&gt;Since the catalog is sorted, the librarian can apply binary search to find the book much faster. They wouldn’t check each title individually but would instead look at the middle entry and decide whether the book is before or after that entry. This process repeats, reducing the number of books the librarian needs to check.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Time Complexity:&lt;/strong&gt; O(log n) (With each step, you halve the number of books you need to check).&lt;/p&gt;

&lt;p&gt;This catalog-based approach, powered by binary search, is much faster than checking every single book, just like how an index in a database speeds up queries.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frfzz918yv75tbwvidham.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frfzz918yv75tbwvidham.png" alt="Comparision non indexed and indexed" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Not Index Every Column?
&lt;/h2&gt;

&lt;p&gt;While indexes are incredibly useful for speeding up searches, creating an index on every column in a database can lead to several issues, making it a bad practice. Let’s explore why:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Performance Overhead During Data Insertion/Updates&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Indexes need to be updated whenever you add, update, or delete data in a table. The more indexes you have, the more work the database has to do.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine a library where every book is indexed by title, author, genre, and publication year. The title index is like a sorted list of book titles, where each title points to the shelf where the book is located. When a new book arrives, the librarian can’t just put it on a shelf randomly—they first need to insert the book’s title in the correct alphabetical position in the title index, update the author index by adding the book under the right author’s name, place it in the correct category in the genre index, and do the same for the publication year index. The more indexes exist, the more time and effort it takes to properly store the book. Similarly, in a database, each index must be updated when a new row is inserted, which slows down write operations significantly if there are too many indexes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Increased Storage Usage&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Each index consumes disk space. The more indexes you create, the more storage is required to maintain them. This can be problematic when dealing with large tables or databases with limited storage.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine a library where, in addition to storing physical books, the librarian also keeps separate catalogs for sorting books by title, author, genre, and publication year. Each of these catalogs takes up space. If the librarian creates a separate catalog for every possible book attribute—such as number of pages, language, publisher, edition, and even cover color—the storage for these catalogs could eventually take up more space than the books themselves! Similarly, in a database, each index requires additional storage. If every column in a large table has an index, the total space used by the indexes could exceed the actual data, leading to inefficient storage usage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Redundant Indexes&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Some columns may not need indexing at all, especially if they're rarely used in queries. Having an index on every column would lead to redundant indexes that don’t improve performance and just add unnecessary overhead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine a library where the librarian creates a separate catalog for every single book detail, including the number of pages, cover color, and even the weight of the book. However, readers never search for books based on their weight or cover color—they only look for title, author, or genre. Maintaining these unnecessary catalogs takes time and space but provides no real benefit. Similarly, in a database, indexing columns that are rarely searched or sorted creates redundant indexes that consume resources without improving performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Decreased Read Performance&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;While indexes speed up reads (searches and lookups), having too many indexes can actually hurt read performance in some situations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine a library with dozens of different catalogs—by title, author, genre, publisher, year, cover color, number of pages, and more. When a reader asks for a book, the librarian must decide which catalog to use. If there are too many catalogs, it takes extra time to check them all and find the best one. Similarly, in a database, when a query is executed, the database must choose the most efficient index. If there are too many indexes, this decision-making process can slow down searches rather than speed them up. Additionally, when new books are added or removed, all these indexes need updating, causing delays and reducing overall performance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/nikita_kutsokon/databases-indexes-part-2-32j7"&gt;Part 2 -&amp;gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Helpful Links 🤓
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Text resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/@rtawadrous/introduction-to-database-indexes-9b488e243cc1" rel="noopener noreferrer"&gt;Introduction To Database Indexing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/sql/databases-indexing" rel="noopener noreferrer"&gt;How Does Database Indexing Work?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.freecodecamp.org/news/database-indexing-at-a-glance-bb50809d48bd/" rel="noopener noreferrer"&gt;An in-depth look at Database Indexing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Video resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Jemuod4wKWo" rel="noopener noreferrer"&gt;what is a database index?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=g2o22C3CRfU" rel="noopener noreferrer"&gt;Big-O Notation in 100 Seconds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=5t1fW3KG920" rel="noopener noreferrer"&gt;SQL Indexes Explained in 20 Minutes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=lYh6LrSIDvY" rel="noopener noreferrer"&gt;Database Indexing for Dumb Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=MFhxShGxHWc&amp;amp;t=74s" rel="noopener noreferrer"&gt;Binary Search Algorithm in 100 Seconds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=BIlFTFrEFOI&amp;amp;t=151s" rel="noopener noreferrer"&gt;SQL indexing best practices | How to make your database FASTER!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=EZ3jBam2IEA" rel="noopener noreferrer"&gt;Database Design 39 - Indexes (Clustered, Nonclustered, Composite Index)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>database</category>
      <category>webdev</category>
      <category>systemdesign</category>
      <category>backend</category>
    </item>
    <item>
      <title>Databases: How Data is Stored on Disk</title>
      <dc:creator>Nikita Kutsokon</dc:creator>
      <pubDate>Sat, 01 Mar 2025 19:57:57 +0000</pubDate>
      <link>https://dev.to/nikita_kutsokon/databases-how-data-is-stored-on-disk-22k8</link>
      <guid>https://dev.to/nikita_kutsokon/databases-how-data-is-stored-on-disk-22k8</guid>
      <description>&lt;p&gt;A database system is designed to store, read, and write data efficiently. It organizes the data into &lt;strong&gt;pages&lt;/strong&gt; and utilizes both &lt;strong&gt;disk storage&lt;/strong&gt; and &lt;strong&gt;RAM&lt;/strong&gt; to manage these pages. But before diving into how databases handle data, let's first explain what RAM is for a better understanding of the article.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is RAM
&lt;/h2&gt;

&lt;p&gt;RAM (Random Access Memory) is the short-term memory of your computer, used to store data and programs that are actively in use. It’s a critical component because it allows the computer to quickly access the information it needs without waiting for slower storage devices like hard drives (HDDs) or solid-state drives (SSDs). RAM is much faster than these storage devices, and when you open a program or file, it gets loaded into RAM to improve performance. The more RAM your computer has, the more data and programs it can store and process at once, which makes multitasking and running demanding applications faster and smoother. However, &lt;strong&gt;RAM is volatile&lt;/strong&gt;, meaning that when you turn off your computer, all the data stored in RAM is erased. This is why it’s essential for running programs in real-time, but it doesn’t hold onto data permanently.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wim6nhzf3yzxhb4e4oi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wim6nhzf3yzxhb4e4oi.png" alt="RAM schema" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Database Stores Data
&lt;/h2&gt;

&lt;p&gt;A database stores data in small blocks called &lt;strong&gt;pages&lt;/strong&gt;, which typically hold several rows of a table or other pieces of data. Each page is a fixed size (usually between 4 KB and 8 KB), and this consistency helps the system efficiently manage large datasets. When data from a table is stored in a database, the rows of that table are divided and placed across multiple pages. Ea*&lt;em&gt;ch page can contain one or more rows&lt;/em&gt;* depending on the size of the rows and the page size. For example, if a table has large rows (such as those with many columns or large text), fewer rows may fit on a page. Smaller rows will allow more to fit on a single page. This method of storing data ensures efficient access, as the database can quickly load entire pages into memory instead of fetching individual rows one by one. This helps speed up queries, especially when large amounts of data need to be processed or retrieved.&lt;/p&gt;

&lt;p&gt;The data is &lt;strong&gt;stored on a disk&lt;/strong&gt;, like a &lt;strong&gt;hard drive (HDD)&lt;/strong&gt; or a &lt;strong&gt;solid-state drive (SSD)&lt;/strong&gt;. These disks preserve the data even when the computer is turned off. However, reading from the disk is slower than reading from the computer's RAM, which is faster but only works while the computer is on. To speed up data access, the database uses a special area in RAM called the buffer pool. This area stores frequently accessed data. Instead of reading small pieces of data one by one, the database reads whole pages at once. These pages are stored on the disk, and when needed, they’re quickly &lt;strong&gt;loaded into RAM&lt;/strong&gt; for faster access.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Database Reads Data
&lt;/h2&gt;

&lt;p&gt;When the database needs to access data, it doesn’t read individual rows or records directly from the disk. Instead, it &lt;strong&gt;reads entire pages&lt;/strong&gt;, which are fixed-size blocks containing multiple rows or pieces of data. The database first checks if the required page is already in the buffer pool. If the page is found in RAM, it can be accessed quickly. If not, the database reads the page from the disk and loads it into RAM for future use. This way, the database minimizes the need to access the slower disk.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Database Writes Data
&lt;/h2&gt;

&lt;p&gt;When the database needs to write data (adding new rows or updating existing data), it &lt;strong&gt;first writes the changes to the buffer pool&lt;/strong&gt; in RAM, not directly to the disk. This is because writing to RAM is much faster. Later, the database writes the changes from RAM to the disk, typically in large batches, to minimize disk access time. This process is called buffering or write-back. To ensure data isn't lost, databases use transaction logs to track changes. If the system crashes, the transaction logs help recover the changes when the system restarts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disk I/O Optimization
&lt;/h2&gt;

&lt;p&gt;Disk I/O (Input/Output) optimization plays a key role in enhancing the performance of databases. Since databases store large volumes of data on disks, which are slower than RAM, minimizing the time spent reading from and writing to these disks is essential. Optimizing disk I/O involves improving how a database interacts with its disk storage, resulting in faster and more responsive system performance. Let's explore some techniques used to achieve this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Buffer Pool (Caching)&lt;/strong&gt;&lt;br&gt;
Think of the buffer pool like a temporary storage area in your computer's memory (RAM). When the database needs data, it first checks if the data is already in the buffer pool. If it is, the database can quickly use it without waiting for it to be read from the slower disk. This speeds up data retrieval, especially for commonly used data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Read-Ahead (Prefetching)&lt;/strong&gt;&lt;br&gt;
Imagine you’re reading a book and you know the next chapter is important. Instead of waiting for each page, you turn several pages ahead. The database does something similar by predicting which data it might need next and loading it into memory ahead of time. This way, the data is ready when needed, reducing delays.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Write-Ahead Logging (WAL)&lt;/strong&gt;&lt;br&gt;
Before the database writes any new data to the disk, it first records the change in a special log file. This is like making a note before making any changes to ensure that if something goes wrong (like a power failure), the database can recover the changes from the log, preventing data loss.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Batching Writes&lt;/strong&gt;&lt;br&gt;
Instead of writing every single change to the disk one by one, the database groups several changes together and writes them all at once. This reduces the number of times the system has to access the disk, making the overall process more efficient.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Disk Striping (RAID)&lt;/strong&gt;&lt;br&gt;
Disk striping is like cutting a file into pieces and storing those pieces on different disks. When the database needs to access the file, it can read from multiple disks at once, which speeds up the process. This is often used in RAID setups to improve performance and ensure the data is safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  HDD vs SSD in Database Storage
&lt;/h2&gt;

&lt;p&gt;When storing data for a database, you can use either &lt;strong&gt;HDD (Hard Disk Drive)&lt;/strong&gt; or &lt;strong&gt;SSD (Solid State Drive)&lt;/strong&gt;. Both have their strengths and weaknesses, so let’s break it down in simple terms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HDD&lt;/strong&gt;&lt;br&gt;
HDDs work by using spinning disks, similar to a record player, with a small arm that moves to read or write data. Because these parts need to physically move, HDDs are slower and take more time to locate and load information. However, they are more affordable per gigabyte, making them a great choice for storing large amounts of data that don’t require fast access. This makes HDDs ideal for &lt;strong&gt;backups, archives, and databases with low traffic,&lt;/strong&gt; where speed is less important than storage capacity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwq3a0fehjyzckridxhq2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwq3a0fehjyzckridxhq2.jpg" alt="HDD structure" width="600" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SSD&lt;/strong&gt;&lt;br&gt;
SSDs use flash memory, a type of non-volatile storage that retains data even when the power is off. Unlike HDDs, which rely on spinning disks, flash memory stores data electronically in memory cells made of transistors. These cells hold an electrical charge to represent binary data (0s and 1s). Because there are no moving parts, SSDs have much lower latency, meaning they can access and transfer data almost instantly, which results in significantly faster read and write speeds. This makes SSDs ideal for &lt;strong&gt;applications that need high-speed performance,&lt;/strong&gt; like real-time analytics and databases with heavy user traffic. Additionally, SSDs are more durable, consume less power, and generate less heat, making them a reliable and energy-efficient choice for high-performance computing&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwyqtpc4asrmuub1lwjg2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwyqtpc4asrmuub1lwjg2.png" alt="SSD Structure" width="671" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Helpful Links 🤓
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Text resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cs186berkeley.net/notes/note3/" rel="noopener noreferrer"&gt;Disk and files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://towardsdatascience.com/how-your-data-is-stored-on-disk-and-memory-8842891da52/" rel="noopener noreferrer"&gt;How your data is stored on disk and memory?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/compare/the-difference-between-ssd-hard-drive/?nc1=h_ls" rel="noopener noreferrer"&gt;What’s the Difference Between an SSD and a Hard Drive?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Video resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=haz2h7_xFDk" rel="noopener noreferrer"&gt;How databases store data on disk?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=OyBwIjnQLtI" rel="noopener noreferrer"&gt;How is data stored in sql database&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=3mmMxgBQ0Yc" rel="noopener noreferrer"&gt;Should I store data "In Memory" or "On Disk"?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=DbxddGtHl70" rel="noopener noreferrer"&gt;How Do Databases Store Tables on Disk? Explained both SSD &amp;amp; HDD&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>backend</category>
      <category>database</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Databases: CAP Theorem</title>
      <dc:creator>Nikita Kutsokon</dc:creator>
      <pubDate>Fri, 28 Feb 2025 09:33:10 +0000</pubDate>
      <link>https://dev.to/nikita_kutsokon/databases-cap-theorem-5c5c</link>
      <guid>https://dev.to/nikita_kutsokon/databases-cap-theorem-5c5c</guid>
      <description>&lt;h2&gt;
  
  
  What is CAP Theorem?
&lt;/h2&gt;

&lt;p&gt;The CAP theorem, also known as Brewer's theorem, is a fundamental concept in &lt;strong&gt;distributed computing&lt;/strong&gt; that states it is impossible for a distributed data store to simultaneously provide more than two out of the following three guarantees:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Consistency&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Availability&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partition Tolerance&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8s36htplv3rm54utcfq9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8s36htplv3rm54utcfq9.png" alt="CAP diagram" width="800" height="796"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Consistency
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Every node in a distributed system sees the same data at the same time. Once a write operation is completed, any subsequent read operation will return the updated value.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Consistency means all parts of the system see the same data at the same time. This is done using methods like &lt;strong&gt;consensus algorithms&lt;/strong&gt;, which make sure all parts agree on the data. It's important for things like banking or inventory systems where accurate data is crucial.&lt;/p&gt;

&lt;p&gt;⚠️ Keeping data consistent can slow down the system and make it less available, especially if parts of the network fail. The system might need to wait for all parts to agree, which can cause delays.&lt;/p&gt;

&lt;h2&gt;
  
  
  Availability
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Every request (read or write) receives a response, regardless of the state of any individual node in the system&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Availability means the system always responds to requests, even if some parts fail. This is achieved by copying data across multiple parts and having backup plans. It's vital for services like social media or online games where being always online is important&lt;/p&gt;

&lt;p&gt;⚠️ Focusing on availability can mean sometimes showing old data, especially if network problems occur. The system might prioritize staying online over having the latest data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Partition Tolerance
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The system continues to operate despite network partitions, where communication between nodes is disrupted&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Partition tolerance means the system keeps working even if parts of the network are disconnected. This is done by handling network failures gracefully. It's essential for apps used in places with poor network connections, like mobile apps&lt;/p&gt;

&lt;p&gt;⚠️ A system that handles network failures must choose between consistency and availability. This choice can affect how reliable and up-to-date the data is during network problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CAP Triangle: Trade-offs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Consistency vs Availability&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the event of a network partition, a system must decide whether to maintain consistency (ensuring all nodes have the same data) or availability (ensuring the system remains operational). This trade-off is critical because it directly impacts how the system behaves when parts of the network are disconnected. Choosing consistency can lead to better data integrity but may result in downtime or slower responses during network issues. Conversely, prioritizing availability ensures the system stays responsive but might serve stale or inconsistent data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Availability vs Partition Tolerance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A system that prioritizes availability and partition tolerance (AP) remains operational during network partitions but may return stale or inconsistent data. This trade-off is common in systems where uptime is more important than immediate data consistency. While this approach ensures high availability, it can lead to temporary data inconsistencies. Users might see outdated information, which can be acceptable in some applications but problematic in others, like financial systems.&lt;/p&gt;

&lt;p&gt;🤓 The most frequent trade-off is between &lt;strong&gt;consistency&lt;/strong&gt; and &lt;strong&gt;availability&lt;/strong&gt;, especially in systems that must handle network partitions. This trade-off is crucial because network partitions are inevitable in distributed systems. Many modern distributed databases and applications opt for eventual consistency to balance this trade-off, ensuring data will become consistent over time as the network stabilizes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1kui3wj1bgymgc2m2ruw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1kui3wj1bgymgc2m2ruw.png" alt="CAP databases" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Consistency(CAP) vs Consistency(ACID)
&lt;/h2&gt;

&lt;p&gt;CAP consistency ensures that all nodes in a distributed system always return the most recent data, focusing on synchronization across replicas, even at the cost of availability during network failures. In contrast, ACID consistency ensures that a database remains in a valid state by enforcing rules and constraints within transactions, preventing partial updates or invalid data. &lt;strong&gt;While CAP consistency is crucial for distributed systems&lt;/strong&gt; like Google Spanner or Zookeeper, &lt;strong&gt;ACID consistency is fundamental for relational databases&lt;/strong&gt; like PostgreSQL and MySQL, ensuring correctness but potentially impacting performance.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwcybuajfs9lbp9dad5j0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwcybuajfs9lbp9dad5j0.png" alt="Consistency(CAP) vs Consistency(ACID)" width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Helpful Links 🤓
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Text resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.ibm.com/think/topics/cap-theorem" rel="noopener noreferrer"&gt;What is the CAP theorem?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.bmc.com/blogs/cap-theorem/#:~:text=The%20CAP%20theorem%20is%20a,or%20availability%E2%80%94but%20not%20both." rel="noopener noreferrer"&gt;CAP Theorem Explained: Consistency, Availability &amp;amp; Partition Tolerance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://talent500.com/blog/cap-theorem-database-selectionguide/" rel="noopener noreferrer"&gt;Navigating the CAP Theorem: A Guide to Selecting the Right Database&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@ngneha090/understanding-the-cap-theorem-balancing-consistency-availability-and-partition-cb11c2b97e2b" rel="noopener noreferrer"&gt;Understanding the CAP Theorem: Balancing Consistency, Availability, and Partition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@ajayverma23/demystifying-the-cap-theorem-understanding-consistency-availability-and-partition-tolerance-446de8452fac" rel="noopener noreferrer"&gt;Demystifying the CAP Theorem: Understanding Consistency, Availability, and Partition Tolerance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Video resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=BHqjEjzAicA" rel="noopener noreferrer"&gt;CAP Theorem Simplified&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=gkg-FAEXIkY" rel="noopener noreferrer"&gt;Friendly Intro To the CAP Theorem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=NKnHgU9nciU" rel="noopener noreferrer"&gt;CAP Theorem: PostgreSQL vs Cassandra&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>backend</category>
      <category>database</category>
      <category>webdev</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Databases: Cursor</title>
      <dc:creator>Nikita Kutsokon</dc:creator>
      <pubDate>Mon, 24 Feb 2025 10:15:00 +0000</pubDate>
      <link>https://dev.to/nikita_kutsokon/databases-cursor-1lib</link>
      <guid>https://dev.to/nikita_kutsokon/databases-cursor-1lib</guid>
      <description>&lt;h2&gt;
  
  
  What is it ?
&lt;/h2&gt;

&lt;p&gt;A cursor in a database acts like a pointer that enables you to handle each row in a result set one at a time. It's similar to a bookmark, helping you move through the rows sequentially. Imagine the cursor as a marker that begins just before the first row of your data. You can advance this marker through the rows, fetching and processing each row individually as you go&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiaj5vraw4mm14yd1vkk0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiaj5vraw4mm14yd1vkk0.png" alt="Cursor vizualization" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's explore the syntax of cursors in SQL using a simple example. This example demonstrates how to declare, open, fetch, and process data using a cursor:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You have a table named Products with columns ProductID, ProductName, and Price. You want to print the name and price of each product&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DECLARE @ProductID INT;
DECLARE @ProductName NVARCHAR(100);
DECLARE @Price DECIMAL(10, 2);

-- Declare the cursor
DECLARE ProductCursor CURSOR FOR
SELECT ProductID, ProductName, Price FROM Products;

-- Open the cursor
OPEN ProductCursor;

-- Fetch the first row into the variables
FETCH NEXT FROM ProductCursor INTO @ProductID, @ProductName, @Price;

-- Loop through the rows
WHILE @@FETCH_STATUS = 0
BEGIN
    -- Print the product name and price
    PRINT 'Product ID: ' + CAST(@ProductID AS NVARCHAR(10)) +
          ', Name: ' + @ProductName +
          ', Price: ' + CAST(@Price AS NVARCHAR(10));

    -- Fetch the next row
    FETCH NEXT FROM ProductCursor INTO @ProductID, @ProductName, @Price;
END;

-- Close and deallocate the cursor
CLOSE ProductCursor;
DEALLOCATE ProductCursor;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why we need it ?
&lt;/h2&gt;

&lt;p&gt;You need a cursor in a database when your task requires detailed, row-by-row processing that cannot be efficiently handled with a single SELECT statement. Here are some key reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a cursor when each row needs different, complex actions based on its data.&lt;/li&gt;
&lt;li&gt;When the order of processing matters, like calculating running totals, a cursor ensures rows are handled in sequence.&lt;/li&gt;
&lt;li&gt;Cursors allow you to run different SQL commands for each row, adapting to each row's data.&lt;/li&gt;
&lt;li&gt;With a cursor, you can handle errors for each row separately, logging issues without stopping the entire process.&lt;/li&gt;
&lt;li&gt;Cursors help apply complex transformation rules to each row individually.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Types of Cursors
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Forward-Only&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Moves in one direction from the first to the last row.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You need to read through a list of customer orders to generate a summary report&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A forward-only cursor is ideal for this task. You open the cursor to fetch each order sequentially, calculate the total sales, and then move to the next order. This type of cursor is efficient for read-only operations where you don't need to revisit previous rows, making it suitable for generating reports or summaries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Static&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Creates a temporary copy of the data, allowing modifications to the underlying data without affecting the cursor.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are generating a monthly sales report and want to ensure that the data remains consistent throughout the report generation process.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A static cursor is perfect for this situation. It takes a snapshot of the data at the time the cursor is opened, ensuring that any changes made to the data by other users do not affect your report. This consistency is crucial for accurate reporting and analysis over a specific period.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Dynamic&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Reflects changes made to the data as you scroll through the cursor.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are monitoring real-time inventory levels and need to react to changes immediately.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A dynamic cursor is suitable here as it reflects changes made to the data as you move through the cursor. If items are added or removed from the inventory while you are processing, the cursor will reflect these changes, allowing you to make real-time adjustments and maintain accurate inventory levels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Keyset-Driven&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Similar to a dynamic cursor but uses a set of keys to track rows. It detects changes to the membership and order of rows but does not reflect changes to the data within the rows.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are processing a list of active user accounts and need to ensure that any new accounts added during the process are included.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A keyset-driven cursor is useful in this case. It uses a set of keys to track rows, detecting changes to the membership and order of rows. If new accounts are added, the cursor will include them in the processing. However, it does not reflect changes to existing accounts (like updating user details) within the rows. This makes it efficient for tasks where row membership is more critical than data updates, ensuring that all relevant rows are processed without missing any new additions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cursor vs Select
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Cursors&lt;/strong&gt; are ideal for detailed, row-by-row processing, such as handling complex logic or sequential operations, like sending personalized emails or calculating running totals. They offer flexibility but can be less efficient due to their row-by-row nature.&lt;/p&gt;

&lt;p&gt;In contrast, &lt;strong&gt;SELECT&lt;/strong&gt; operations are optimized for set-based processing, efficiently retrieving and manipulating multiple rows at once. They are best for simple aggregations and read-only queries, like generating sales reports. SELECT operations are generally more performant, especially with large datasets.&lt;/p&gt;

&lt;p&gt;The choice between using a cursor and a SELECT operation depends on your task's complexity and performance needs. Use cursors for complex, row-level tasks and SELECT for simpler, set-based data retrieval.&lt;/p&gt;

&lt;h2&gt;
  
  
  Helpful Links 🤓
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Text resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/office/client-developer/access/desktop-database-reference/what-is-a-cursor" rel="noopener noreferrer"&gt;What is a cursor?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.geeksforgeeks.org/what-is-cursor-in-sql/" rel="noopener noreferrer"&gt;What is Cursor in SQL ?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.codeproject.com/Articles/5326773/What-is-a-Database-Cursor" rel="noopener noreferrer"&gt;What is a Database Cursor?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Video resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=N0z3gVHIxEo&amp;amp;t=19s" rel="noopener noreferrer"&gt;What is a Cursor?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=WDJRRNCGIRs" rel="noopener noreferrer"&gt;don’t use “offset” in your SQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=zwDIN04lIpc&amp;amp;t=372s" rel="noopener noreferrer"&gt;Pagination in MySQL - offset vs. cursor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>backend</category>
      <category>systemdesign</category>
      <category>database</category>
    </item>
    <item>
      <title>Databases: ACID &amp; BASE</title>
      <dc:creator>Nikita Kutsokon</dc:creator>
      <pubDate>Sun, 23 Feb 2025 11:41:57 +0000</pubDate>
      <link>https://dev.to/nikita_kutsokon/databases-acid-base-282p</link>
      <guid>https://dev.to/nikita_kutsokon/databases-acid-base-282p</guid>
      <description>&lt;h2&gt;
  
  
  ACID
&lt;/h2&gt;

&lt;p&gt;In the realm of database management, ensuring the reliability and integrity of data is paramount. This is where the ACID principles come into play. ACID, an acronym for &lt;strong&gt;Atomicity&lt;/strong&gt;, &lt;strong&gt;Consistency&lt;/strong&gt;, &lt;strong&gt;Isolation&lt;/strong&gt;, and &lt;strong&gt;Durability&lt;/strong&gt;, represents a set of properties that guarantee reliable processing of database transactions. These principles are foundational to traditional relational database management systems (RDBMS) and are crucial for applications where data accuracy and consistency are non-negotiable. &lt;/p&gt;

&lt;p&gt;Before we start, let's recap what is the transaction:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transaction&lt;/strong&gt; - is a sequence of one or more queries executed as a single unit of work. The main principle of a transaction is &lt;u&gt;"all or nothing"&lt;/u&gt;, meaning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If all queries in the transaction succeed, the changes are safely saved in the database.&lt;/li&gt;
&lt;li&gt;If any query in the transaction fails, all changes are undone, restoring the database to its original state before the transaction started.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ When changes are saved, we say the transaction is &lt;strong&gt;committed&lt;/strong&gt;. If changes are undone, the transaction is &lt;strong&gt;rolled back&lt;/strong&gt; ⚠️&lt;/p&gt;

&lt;p&gt;Imagine you are buying a laptop from an online store. When you click "Place Order", several things must happen in the database:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check if the laptop is in stock.&lt;/li&gt;
&lt;li&gt;Deduct the laptop from the stock.&lt;/li&gt;
&lt;li&gt;Charge your credit card.&lt;/li&gt;
&lt;li&gt;Create an order record in the system.&lt;/li&gt;
&lt;li&gt;Send a confirmation email.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can think of it as a single unit of work. Let's also consider that each query interacts with various tables:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8g54b2khnrnn4jl2qd97.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8g54b2khnrnn4jl2qd97.png" alt="Transaction example of place order" width="800" height="167"&gt;&lt;/a&gt;&lt;br&gt;
🤓 You can ask, why in this scenario i need a transaction, well, lets see what will happen if we didnt use it: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The laptop is taken from stock, but the payment fails — now the store has fewer laptops but no money.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhez3qsu1jvix68bp0l5.png" alt="Transaction example: failure" width="800" height="278"&gt;
&lt;/li&gt;
&lt;li&gt;The payment goes through, but there’s no order record — you paid, but the store has no idea what you bought!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using a transaction keeps everything in sync. If something goes wrong, it rolls back all the steps to make sure nothing is left half-finished. Let's consider an example where all changes are committed only if every query is successful&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd303exf9rjdcpzsvcy77.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd303exf9rjdcpzsvcy77.png" alt="Transaction example: success" width="800" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A transaction makes sure everything is done correctly or nothing is done at all!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you are familiar with SQL, you can also see how this would look in a query (pseudocode):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BEGIN TRANSACTION;

-- 1. Check if the laptop is in stock
SELECT stock_quantity FROM laptops WHERE laptop_id = 1;

-- 2. Deduct the laptop from the stock
UPDATE laptops SET stock_quantity = stock_quantity - 1 WHERE laptop_id = 1;

-- 3. Charge the credit card (simplified)
INSERT INTO payments (user_id, amount) VALUES (123, 1000);

-- 4. Create an order record in the system
INSERT INTO orders (user_id, laptop_id, order_date) VALUES (123, 1, '2025-02-23');

-- 5. Send a confirmation email (simplified)
INSERT INTO email_queue (user_id, email_type, status) VALUES (123, 'order_confirmation', 'pending');

-- 6. If everything is successful, commit the transaction
COMMIT;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we understand what a transaction is, let's explore what the ACID acronym stands for ! 🎉🎉🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Atomicity
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;All or nothing. A transaction either fully completes or has no effect.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Atomicity is one of the core principles of database transactions, ensuring that a transaction is treated as a single, indivisible unit of work. This means:&lt;br&gt;
✅ &lt;strong&gt;All-or-Nothing&lt;/strong&gt; – If a transaction completes successfully, all its changes are saved.&lt;br&gt;
✅ &lt;strong&gt;Rollback on Failure&lt;/strong&gt; – If any part of the transaction fails, all changes are discarded, keeping the database unchanged.&lt;/p&gt;

&lt;p&gt;🔑 Key points that define atomacity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;All-or-Nothing Execution&lt;/strong&gt; – A transaction is either fully completed or not executed at all&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rollback on Failure&lt;/strong&gt; – If one query in the transaction fails, all previous successful queries are undone&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Partial Updates&lt;/strong&gt; – If a problem occurs, the database remains as if the transaction never happened&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🚨 What happens if Atomicity is NOT ensured?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The payment succeeds, but the stock update fails → You are charged, but the store doesn't reserve your laptop!&lt;/li&gt;
&lt;li&gt;The stock is updated, but the payment fails → The laptop is removed from inventory without receiving money.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Consistency
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Rules are followed. A transaction moves the database from one valid state to another.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It ensures that a transaction brings the database from one valid state to another. In other words, a transaction must always follow the rules, constraints, and data integrity of the database, maintaining its integrity throughout the process. This means:&lt;br&gt;
✅ &lt;strong&gt;Valid Transitions&lt;/strong&gt; – A transaction will only commit if it preserves the database's rules and integrity. &lt;br&gt;
✅ &lt;strong&gt;Invalid Transitions&lt;/strong&gt; – If the transaction violates any of the database’s constraints (data type rules, referential integrity), it will be rolled back.&lt;/p&gt;

&lt;p&gt;🔑 Key Points that Define Consistency:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Integrity Preservation&lt;/strong&gt; – The database must transition from one consistent state to another, adhering to defined rules ( constraints, triggers, business rules). &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Invalid Data&lt;/strong&gt; – Transactions that would result in invalid data (violating primary key, foreign key, or unique constraints) are not allowed to commit. &lt;/li&gt;
&lt;li&gt;Enforcing Constraints – All database rules such as constraints (like unique values, not null, foreign keys) are maintained throughout the transaction. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Rollback&lt;/strong&gt; – If a transaction causes an inconsistency, the database will automatically roll back to its last consistent state, ensuring no corrupt data is saved. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Partial Data&lt;/strong&gt; – Transactions that leave data in an inconsistent state (such as violating business logic) will not complete.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🚨 What happens if Consistency is NOT ensured?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Payment fails after inventory update -&amp;gt; If the stock is deducted but payment is not successful (due to a system error), the database may reflect that the laptop has been sold, but the payment was not processed. This creates inconsistency, as the stock is reduced without receiving money.&lt;/li&gt;
&lt;li&gt;Order without valid data -&amp;gt; If the transaction violates integrity constraints (an order is created without a valid customer ID or payment), the database might store incomplete or invalid data.&lt;/li&gt;
&lt;li&gt;Incomplete transactions -&amp;gt; The database might store records with missing or invalid information, leading to errors in reporting, business logic, or even operational decisions.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Isolation
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Transactions don't interfere. Each transaction is independent of others happening at the same time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Isolation is one of the key principles of the ACID properties in database transactions. It ensures that each transaction is executed in isolation from other concurrent transactions. This means that even if multiple transactions are running at the same time, the changes made by each transaction are not visible to others until they are fully committed, preventing them from interfering with each other. This means:&lt;br&gt;
✅ &lt;strong&gt;Independent Transactions&lt;/strong&gt; – Transactions are isolated from each other, ensuring that they don’t affect each other’s results. &lt;br&gt;
✅ &lt;strong&gt;No Interference&lt;/strong&gt; – Even though transactions are executed simultaneously, one transaction’s data changes will not be visible to another transaction until fully committed.&lt;/p&gt;

&lt;p&gt;🔑 Key Points that Define Isolation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transaction Independence&lt;/strong&gt; – Each transaction is executed as if it is the only transaction running in the system. No transaction can access the intermediate (uncommitted) data of another transaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prevents Dirty Reads&lt;/strong&gt; – A transaction should not read data that is in the middle of being modified by another transaction (dirty reads). &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prevents Non-Repeatable Reads&lt;/strong&gt; – Data read by a transaction cannot change before it is completed, ensuring that subsequent reads within the same transaction give consistent results. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prevents Phantom Reads&lt;/strong&gt; – A transaction should not see new rows that were added or deleted by another transaction after it started. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolation Levels&lt;/strong&gt; – Isolation can be adjusted with different levels (Read Uncommitted, Read Committed, Repeatable Read, Serializable), offering a trade-off between performance and strict isolation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🚨 What happens if Isolation is NOT ensured?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dirty Reads -&amp;gt; One transaction might read uncommitted changes made by another transaction. For example, Customer A might deduct the stock of the laptop, but Customer B reads the same stock quantity before Customer A commits the transaction.&lt;/li&gt;
&lt;li&gt;Lost Updates -&amp;gt; If two transactions are modifying the same data at the same time, one transaction might overwrite the changes of the other, leading to lost data.&lt;/li&gt;
&lt;li&gt;Inconsistent Data -&amp;gt; A transaction might use data that is still being modified by another transaction, leading to inconsistent results and potential errors.&lt;/li&gt;
&lt;li&gt;Phantom Reads -&amp;gt; A transaction may not see the same set of rows (inventory) every time it queries the database if another transaction inserts, deletes, or updates rows during the course of the first transaction.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Durability
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Changes stick. Once a transaction is complete, its changes are permanent, even if the system fails.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This principle ensures that once a transaction has been committed, its changes are permanent, even in the event of a system failure (power loss or crash). This means: &lt;br&gt;
✅ &lt;strong&gt;Permanent Changes&lt;/strong&gt; – Once a transaction is committed, the changes are guaranteed to persist, no matter what happens next. &lt;br&gt;
✅ &lt;strong&gt;System Failures Don't Lose Data&lt;/strong&gt; – Even if the database crashes after the transaction commits, the changes will remain intact.&lt;/p&gt;

&lt;p&gt;🔑 Key Points that Define Durability&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Permanent Commit&lt;/strong&gt; – Once a transaction is successfully committed, its results are saved permanently to disk and will survive system crashes. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crash Recovery&lt;/strong&gt; – In the event of a crash, the database can recover to its last committed state, ensuring no data loss. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Integrity After Failure&lt;/strong&gt; – Even if there is a failure after the transaction is committed, the database will never revert to a previous, inconsistent state. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Rollback After Commit&lt;/strong&gt; – After a transaction is committed, there’s no way to undo its changes unless explicitly done by another transaction. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guarantee of Persistence&lt;/strong&gt; – Durability guarantees that once the transaction is completed, it becomes part of the database history.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🚨 What happens if Durability is NOT ensured?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;After committing a transaction, if the system crashes, any committed changes could be lost -&amp;gt; Payment might be processed, but the system could fail before saving the updated inventory or generating the order record.&lt;/li&gt;
&lt;li&gt;When the system recovers, the transaction could be lost -&amp;gt; inconsistent data such as uncharged payments, incorrect stock levels, or missing orders.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;📝 In summary, ACID provides the foundation for secure and efficient transaction management, helping prevent errors, inconsistencies, and data corruption, which ultimately builds trust in database systems and ensures smooth operations for end-users and businesses.&lt;/p&gt;




&lt;h2&gt;
  
  
  BASE
&lt;/h2&gt;

&lt;p&gt;With the advent of NoSQL databases, a new paradigm emerged for managing and manipulating data, emphasizing flexibility and scalability over rigid consistency. This shift led to the development of the BASE model, which stands for Basically Available, Soft state, Eventual consistency. Unlike traditional relational databases that prioritize strict consistency and transactional integrity, the BASE model embraces a more relaxed approach to data management. The BASE model is designed to address the challenges of distributed systems, where data is spread across multiple nodes and consistency is not always immediate. It allows for high availability and partition tolerance, making it ideal for large-scale applications where real-time consistency is less critical than continuous accessibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basically Available
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The system always provides a response to queries, but the data might not be the most recent.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imagine you have a distributed database with multiple nodes. If one node fails, the system can still respond to queries using data from other nodes, even if that data is slightly outdated. This ensures that the system is always available to users, even during failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Soft State
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The system's state can change over time, even without new input, due to eventual consistency.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a shopping cart application, if you add an item to your cart, the system might not immediately reflect this change across all servers. Over time, the system will update and synchronize, ensuring that all servers eventually show the same state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Eventual Consistency
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;If no new updates are made, all accesses to a given data item will eventually return the last updated value.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Suppose you update your profile picture on a social media platform. Due to eventual consistency, some users might see your old profile picture for a short period. However, after some time, everyone will see the new picture as the system synchronizes the updates across all servers.&lt;/p&gt;

&lt;p&gt;📝 In summary, BASE provides a flexible and scalable approach to database management, prioritizing availability and eventual consistency over strict transaction rules. This makes it ideal for distributed systems, allowing businesses to handle large-scale data efficiently while maintaining system responsiveness and fault tolerance.&lt;/p&gt;




&lt;h2&gt;
  
  
  ACID vs BASE
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Consistency &amp;amp; Availability&lt;/strong&gt; - ACID prioritizes strong consistency and reliability, making it suitable for critical applications where data integrity is paramount. BASE prioritizes availability and partition tolerance, making it suitable for large-scale, distributed systems where immediate consistency is less critical.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt; - BASE systems are generally more scalable due to their relaxed consistency requirements, making them suitable for high-traffic applications. ACID systems can be less scalable due to the overhead of maintaining strong consistency. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt; - ACID is preferred for traditional enterprise applications like banking and healthcare, where data integrity and consistency are crucial. BASE is preferred for modern web applications, IoT, and real-time analytics, where scalability and availability are more important.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;📝 In summary, the choice between ACID and BASE depends on the specific requirements of the application, particularly the trade-offs between consistency, availability, and scalability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Helpful Links 🤓
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Text resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.lifewire.com/abandoning-acid-in-favor-of-base-1019674" rel="noopener noreferrer"&gt;What Is BASE in Database Engineering?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/resources/basics/databases/acid-transactions" rel="noopener noreferrer"&gt;A Guide to ACID Properties in Database Management Systems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/compare/the-difference-between-acid-and-base-database/?nc1=h_ls" rel="noopener noreferrer"&gt;What’s the Difference Between an ACID and a BASE Database?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.freecodecamp.org/news/acid-databases-explained/" rel="noopener noreferrer"&gt;ACID Databases – Atomicity, Consistency, Isolation &amp;amp; Durability Explained&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Video resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=GAe5oB742dw" rel="noopener noreferrer"&gt;ACID Properties in Databases With Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=rqotnwpwPoA" rel="noopener noreferrer"&gt;ACID vs BASE SQL vs NoSQL Database Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=pomxJOFVcQs" rel="noopener noreferrer"&gt;Relational Database ACID Transactions (Explained by Example)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=6mLWpDFeR0c" rel="noopener noreferrer"&gt;What are ACID Transactions? | Which databases are ACID compliant?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>backend</category>
      <category>database</category>
      <category>systemdesign</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Databases: Partitioning &amp; Sharding</title>
      <dc:creator>Nikita Kutsokon</dc:creator>
      <pubDate>Wed, 19 Feb 2025 16:31:37 +0000</pubDate>
      <link>https://dev.to/nikita_kutsokon/databases-partitioning-sharding-4l50</link>
      <guid>https://dev.to/nikita_kutsokon/databases-partitioning-sharding-4l50</guid>
      <description>&lt;p&gt;As databases grow in size and complexity, ensuring efficient storage, retrieval, and management of data becomes a significant challenge. Two key strategies to handle large-scale data distribution are &lt;strong&gt;partitioning&lt;/strong&gt; and &lt;strong&gt;sharding&lt;/strong&gt;. While both techniques involve breaking down data into smaller segments, they serve different purposes and are used in different scenarios.&lt;/p&gt;




&lt;h2&gt;
  
  
  Partitioning
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Partitioning is splitting a database table into smaller parts within one database&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;✨ Think of a database as a club with different rooms for different music genres. Partitioning is how you decide who goes where—pop lovers in one room, rock fans in another. ✨&lt;/p&gt;

&lt;h2&gt;
  
  
  Vertical &amp;amp; Horizontal Partitioning
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Vertical Partitioning&lt;/strong&gt; - splits a table into multiple tables &lt;u&gt;by columns&lt;/u&gt;. Each new table contains a subset of the columns from the original table, let's look at an example:&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Original Table&lt;/u&gt;: &lt;br&gt;
&lt;em&gt;customers (customer_id, name, email, address, phone_number)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Partitioned Tables&lt;/u&gt;:&lt;br&gt;
&lt;em&gt;customer_details (customer_id, name, email)&lt;br&gt;
customer_contact (customer_id, address, phone_number)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Horizontal partitioning&lt;/strong&gt; - splits a table into multiple tables &lt;u&gt;by rows&lt;/u&gt;. Each new table contains a subset of the rows from the original table, let's explore an example:&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Original Table&lt;/u&gt;:&lt;br&gt;
&lt;em&gt;sales (sale_id, product_id, sale_date, amount)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Partitioned Tables:&lt;/u&gt;&lt;br&gt;
&lt;em&gt;sales_2023 (sales from 2023)&lt;br&gt;
sales_2024 (sales from 2024)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Types of partitioning
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. By range&lt;/strong&gt;: &lt;em&gt;Data is split based on a range of values (dates or numbers)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Suppose you have a music database and you want to partition the data based on the release year of the songs: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;u&gt;Partition&lt;/u&gt;: &lt;em&gt;Songs released from 1960 to 1969&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;Partition&lt;/u&gt;: &lt;em&gt;Songs released from 1970 to 1979&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;Partition&lt;/u&gt;: &lt;em&gt;Songs released from 1980 to 1989&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;Partition&lt;/u&gt;: &lt;em&gt;Songs released from 1990 to 1999&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE songs (
    song_id INT,
    title VARCHAR(100),
    artist VARCHAR(100),
    release_year INT
)
PARTITION BY RANGE (release_year) (
    PARTITION p1 VALUES LESS THAN (1970),
    PARTITION p2 VALUES LESS THAN (1980),
    PARTITION p3 VALUES LESS THAN (1990),
    PARTITION p4 VALUES LESS THAN (2000)
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;😎 Range partitioning is ideal when you need to analyze data over specific time periods. For example, if you want to study the evolution of music genres over decades. It also useful for archiving old data while keeping recent data easily accessible. For instance, you can archive songs from the 1960s and 1970s while keeping newer songs in more frequently accessed partitions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. By list&lt;/strong&gt;: &lt;em&gt;Data is split based on predefined categories (regions or groups)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Suppose you have a music database and you want to partition the data based on the genre of the songs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;u&gt;Partition&lt;/u&gt;: &lt;em&gt;Rock songs&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;Partition&lt;/u&gt;: &lt;em&gt;Pop songs&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;Partition&lt;/u&gt;: &lt;em&gt;Jazz songs&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;Partition&lt;/u&gt;: &lt;em&gt;Classical songs&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE songs (
    song_id INT,
    title VARCHAR(100),
    artist VARCHAR(100),
    genre VARCHAR(50)
)
PARTITION BY LIST (genre) (
    PARTITION p1 VALUES IN ('Rock'),
    PARTITION p2 VALUES IN ('Pop'),
    PARTITION p3 VALUES IN ('Jazz'),
    PARTITION p4 VALUES IN ('Classical')
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;😎 List partitioning is best when you frequently query data based on specific categories, such as music genres, allowing for efficient retrieval of songs within each genre.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. By hash&lt;/strong&gt;: &lt;em&gt;Data is evenly split using a hashing function&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Suppose you have a music database and you want to partition the data evenly based on the song ID using a hashing function:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;u&gt;Partition&lt;/u&gt;: &lt;em&gt;Songs with song_id % 4 = 0&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;Partition&lt;/u&gt;: &lt;em&gt;Songs with song_id % 4 = 1&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;Partition&lt;/u&gt;: &lt;em&gt;Songs with song_id % 4 = 2&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;Partition&lt;/u&gt;: &lt;em&gt;Songs with song_id % 4 = 3&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE songs (
    song_id INT,
    title VARCHAR(100),
    artist VARCHAR(100),
    genre VARCHAR(50)
)
PARTITION BY HASH (song_id)
PARTITIONS 4;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;😎 Hash partitioning is suitable when you need to ensure an even distribution of data across partitions, preventing hotspots and balancing the load evenly, especially useful for large datasets with uniform access patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pros &amp;amp; Cos
&lt;/h2&gt;

&lt;p&gt;🟢 &lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Improved Performance&lt;/strong&gt; - queries that access a small portion of the data can be faster because they only need to scan relevant partitions. Indexing can be more efficient, as smaller indexes are faster to search.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easier Management&lt;/strong&gt; - administrative tasks like backups and archiving can be performed on individual partitions rather than the entire table. Maintenance operations can be done on a per-partition basis, reducing downtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔴 &lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complexity&lt;/strong&gt; - designing and implementing an effective partitioning strategy can be complex and requires careful planning.
It may require additional administrative overhead to manage partitions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application Changes&lt;/strong&gt; - existing applications may need to be modified to take full advantage of partitioning.
Queries may need to be rewritten to optimize for partitioned tables.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Partitioning is most beneficial for very large tables. Smaller tables may not see significant benefits and could even experience performance degradation&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Sharding
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Sharding is splitting a database into smaller, independent databases (shards), where each shard stores a portion of the data&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;✨ Sharding is like hosting your party in multiple locations—one club for the 90s hits, another for techno. Each place handles its own crowd. ✨&lt;/p&gt;

&lt;h2&gt;
  
  
  Types of sharding
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Ranged/Dynamic Sharding&lt;/strong&gt;: &lt;em&gt;Data is allocated to shards based on a predefined range of values from a specific field (shard key)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;😎 Suitable for datasets where queries often target specific ranges of data, such as date ranges or numerical sequences. For instance, consider this case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;u&gt;Shard A&lt;/u&gt;: Records with IDs from 0 to 19&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;Shard B&lt;/u&gt;: Records with IDs from 20 to 39&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;Shard C&lt;/u&gt;: Records with IDs from 40 to 50&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ Effective shard keys should have high cardinality and well-distributed frequency to avoid unbalanced shards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Algorithmic/Hashed Sharding&lt;/strong&gt;:&lt;em&gt;Data is allocated to shards using a hash function applied to a field or set of fields&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;😎 Ideal for evenly distributing data across shards when a suitable shard key is not available. To give you an idea, here’s an example:&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Hash Value&lt;/u&gt; = ID % Number of Shards&lt;/p&gt;

&lt;p&gt;⚠️ Can lead to increased broadcast operations and complex resharding processes when the number of shards changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Entity/Relationship-Based Sharding&lt;/strong&gt;: &lt;em&gt;Related data is kept together on the same physical shard.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;😎 Effective in relational databases where related data is frequently accessed together, reducing the need for broadcast operations. Suppose we take this scenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;u&gt;Shard A&lt;/u&gt;: User data and related payment methods for users A-M&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;Shard B&lt;/u&gt;: User data and related payment methods for users N-Z&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ Requires careful planning to ensure related data is correctly grouped and managed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Geography-Based Sharding&lt;/strong&gt;: &lt;em&gt;Data is allocated to shards based on geographic information, with shards often located in corresponding geographic regions.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;😎 Improves performance and reduces latency by storing data closer to the users accessing it. As an illustration, let’s look at this example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;u&gt;Shard A&lt;/u&gt;: Data for users in North America&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;Shard B&lt;/u&gt;: Data for users in Europe&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ Effective for global applications where data locality is important for performance and compliance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pros &amp;amp; Cos
&lt;/h2&gt;

&lt;p&gt;🟢 &lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt; - sharding allows databases to scale horizontally by distributing data across multiple servers. This makes it easier to handle large volumes of data and high traffic loads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt; - by distributing data and queries across multiple shards, you can improve query performance and reduce latency, as each shard handles a smaller portion of the data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High Availability&lt;/strong&gt; - sharding can enhance availability by isolating failures to individual shards. If one shard goes down, the others can continue to operate, minimizing downtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fault Isolation&lt;/strong&gt; - issues in one shard do not necessarily affect others, which can improve the overall reliability of the system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geographic Distribution&lt;/strong&gt; - sharding allows data to be distributed across different geographic locations, which can reduce latency for users in different regions and comply with data sovereignty regulations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🔴 &lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complexity&lt;/strong&gt; - implementing and managing a sharded database architecture can be complex. It requires careful planning and expertise to ensure data is distributed and accessed efficiently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Consistency&lt;/strong&gt; - Maintaining data consistency across shards can be challenging, especially in environments where data changes frequently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query Complexity&lt;/strong&gt; - queries that span multiple shards can be more complex to implement and may require additional logic to aggregate results from different shards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operational Overhead&lt;/strong&gt; - sharding introduces additional operational overhead, including the need to manage multiple database instances and ensure they are properly synchronized.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource Management&lt;/strong&gt; - each shard requires its own resources (e.g., CPU, memory), which can lead to increased infrastructure costs and the need for more sophisticated resource management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backup and Recovery&lt;/strong&gt; - backing up and recovering data from a sharded database can be more complex compared to a single database instance, as each shard needs to be managed individually.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Sharding improves scalability by distributing data across multiple databases. It’s useful for large-scale systems but adds complexity. Smaller databases may not benefit&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Partitioning vs Sharding
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F67fq95kovt6ewc7fok2d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F67fq95kovt6ewc7fok2d.png" alt="Partitioning and sharding comperision" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Helpful Links 🤓
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Text resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/what-is/database-sharding/#:~:text=A%20growing%20database%20consumes%20more,down%20the%20application%20for%20maintenance." rel="noopener noreferrer"&gt;Sharding AWS team&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/resources/products/capabilities/database-sharding-explained" rel="noopener noreferrer"&gt;Sharding MongoDb team&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://planetscale.com/blog/sharding-vs-partitioning-whats-the-difference" rel="noopener noreferrer"&gt;Sharding vs Partitioning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.timescale.com/learn/when-to-consider-postgres-partitioning" rel="noopener noreferrer"&gt;When to Consider Postgres Partitioning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.brentozar.com/archive/2012/03/how-decide-if-should-use-table-partitioning/" rel="noopener noreferrer"&gt;How To Decide if You Should Use Table Partitioning&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Video resources:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=XP98YCr-iXQ" rel="noopener noreferrer"&gt;What is Database Sharding?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=KWyVn0aC3kc" rel="noopener noreferrer"&gt;Database Sharding vs Partitioning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=JepwOrjeLnk" rel="noopener noreferrer"&gt;Sharding strategies: lookup-based, range-based, and hash-based&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=be6PLMKKSto" rel="noopener noreferrer"&gt;The Basics of Database Sharding and Partitioning in System Design&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>backend</category>
      <category>database</category>
      <category>systemdesign</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
