<?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: Guangyong</title>
    <description>The latest articles on DEV Community by Guangyong (@yangguangyong).</description>
    <link>https://dev.to/yangguangyong</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%2F2957346%2F8825b340-eb54-4218-bb57-786592c06f9e.jpeg</url>
      <title>DEV Community: Guangyong</title>
      <link>https://dev.to/yangguangyong</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yangguangyong"/>
    <language>en</language>
    <item>
      <title>The Seven Types of Locks in InnoDB</title>
      <dc:creator>Guangyong</dc:creator>
      <pubDate>Tue, 20 May 2025 11:49:37 +0000</pubDate>
      <link>https://dev.to/yangguangyong/the-seven-types-of-locks-in-innodb-5h0a</link>
      <guid>https://dev.to/yangguangyong/the-seven-types-of-locks-in-innodb-5h0a</guid>
      <description>&lt;p&gt;MySQL is currently the most widely used relational database in the world, and InnoDB is its most popular storage engine. InnoDB is renowned for its strong performance under high concurrency and large data volumes. This performance is closely tied to its sophisticated locking mechanisms.&lt;/p&gt;

&lt;p&gt;In total, InnoDB supports seven types of locks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auto-Increment Locks&lt;/li&gt;
&lt;li&gt;Shared and Exclusive Locks&lt;/li&gt;
&lt;li&gt;Intention Locks&lt;/li&gt;
&lt;li&gt;Insert Intention Locks&lt;/li&gt;
&lt;li&gt;Record Locks&lt;/li&gt;
&lt;li&gt;Gap Locks&lt;/li&gt;
&lt;li&gt;Next-Key Locks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scenario: Given a table t(id AUTO_INCREMENT, name) using the default isolation level REPEATABLE READ (RR), suppose it has existing rows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;li&lt;/span&gt;  
&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yang&lt;/span&gt;  
&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chen&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Transaction A runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'xxx'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;-- not yet committed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Transaction B runs later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ooo'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Question: &lt;strong&gt;Will Transaction B be blocked?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Analysis: InnoDB avoids phantom reads under RR by applying locking mechanisms. Here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Transaction A inserts a row (4, 'xxx') via the auto-increment column.&lt;/li&gt;
&lt;li&gt;If Transaction B proceeds without being blocked, it will insert (5, 'ooo').&lt;/li&gt;
&lt;li&gt;Later, Transaction A inserts another row: (6, 'xxoo').&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When A executes:&lt;br&gt;
&lt;/p&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;t&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;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It retrieves rows 4 and 6 but not 5, as uncommitted changes from B aren't visible under RR. This gap (missing 5) appears like a phantom, breaking the assumption of continuity for auto-increment fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auto-Increment Locks
&lt;/h2&gt;

&lt;p&gt;An Auto-Increment Lock is a special table-level lock taken during inserts into AUTO_INCREMENT columns to ensure consistent, gap-free key generation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;From the official documentation:&lt;/p&gt;

&lt;p&gt;An AUTO-INC lock is a special table-level lock taken by transactions inserting into tables with AUTO_INCREMENT columns. In the simplest case, if one transaction is inserting values into the table, any other transactions must wait to do their own inserts into that table, so that rows inserted by the first transaction receive consecutive primary key values.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To configure its behaviour, the innodb_autoinc_lock_mode parameter can be adjusted.&lt;/p&gt;

&lt;h3&gt;
  
  
  What if it’s not AUTO_INCREMENT?
&lt;/h3&gt;

&lt;p&gt;With a table t(id UNIQUE PRIMARY KEY, name) and existing records:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;li&lt;/span&gt;  
&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yang&lt;/span&gt;  
&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chen&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If Transaction A inserts id=11 and not yet committed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xxx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and Transaction B inserts id=12 concurrently,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ooo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;auto-increment locks are not used. What locks are applied, and whether blocking occurs, will be discussed later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shared and Exclusive Locks
&lt;/h2&gt;

&lt;p&gt;InnoDB implements standard row-level locking, including Shared (S) and Exclusive (X) locks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A transaction must acquire an S-lock to read a row.&lt;/li&gt;
&lt;li&gt;An X-lock is required to modify or delete a row.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compatibility Matrix:&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%2Ffh31mjhp8k4fo8q3nen4.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%2Ffh31mjhp8k4fo8q3nen4.png" alt="Image description" width="604" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple S-locks can coexist → concurrent reads allowed.&lt;/li&gt;
&lt;li&gt;X-locks are exclusive → only one transaction can write or read-write.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Drawback: Limited parallelism in high-concurrency systems.&lt;br&gt;
Solution: InnoDB utilises Multi-Version Concurrency Control (MVCC) to improve performance&lt;/p&gt;
&lt;h2&gt;
  
  
  Intention Locks
&lt;/h2&gt;

&lt;p&gt;InnoDB uses multiple granularity locking, allowing row-level and table-level locks to coexist. This is enabled via Intention Locks. An intention lock signals a transaction's intent to acquire future S or X locks on specific rows. It exists only at the table level.&lt;/p&gt;

&lt;p&gt;Types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IS (Intention Shared): Intends to acquire S-locks on some rows.&lt;/li&gt;
&lt;li&gt;IX (Intention Exclusive): Intends to acquire X-locks on some rows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;select ... lock in share mode → sets IS-lock.&lt;/li&gt;
&lt;li&gt;select ... for update → sets IX-lock.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compatibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IS and IX locks are not mutually exclusive, but they conflict with S/X locks.&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%2Far23jmhebk3jsbftvtx7.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%2Far23jmhebk3jsbftvtx7.png" alt="Image description" width="534" height="244"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Insert Intention Locks
&lt;/h2&gt;

&lt;p&gt;Do inserts require strong exclusive locks like updates/deletes? &lt;/p&gt;

&lt;p&gt;Not always. This is where Insert Intention Locks, a subset of Gap Locks, come in. These are index-based locks that allow concurrent inserts within the same index range, as long as they don’t conflict.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;From the official docs:&lt;br&gt;
Insert Intention Lock signals the intent to insert in such a way that multiple transactions inserting into the same index gap need not wait for each other if they are not inserting at the same position within the gap.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example: table with unique PK, InnoDB, RR:&lt;br&gt;
t(id unique PK, name);&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;li&lt;/span&gt;  
&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yang&lt;/span&gt;  
&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chen&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Transaction A inserts id=11, not yet committed&lt;/li&gt;
&lt;li&gt;Transaction B inserts id=12&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Although both operate in the same index gap, their insert positions don’t conflict. Thus:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Insert Intention Locks are used.&lt;/li&gt;
&lt;li&gt;Transaction B is not blocked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Summary of Lock Strategies So Far:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shared Locks (S) enable concurrent reads in InnoDB.&lt;/li&gt;
&lt;li&gt;Exclusive Locks (X) ensure serialised update/delete in InnoDB.&lt;/li&gt;
&lt;li&gt;Insert Intention Locks enable concurrent inserts in InnoDB.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Record Locks
&lt;/h2&gt;

&lt;p&gt;Record Locks apply to individual index records. Example:&lt;br&gt;
&lt;/p&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;t&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="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;update&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This locks the index entry with id=1, preventing concurrent modifications.&lt;/p&gt;

&lt;p&gt;Note:&lt;br&gt;
Regular reads like select * from t where id = 1 do not lock the row — these are snapshot reads, handled by MVCC.&lt;/p&gt;
&lt;h2&gt;
  
  
  Gap Locks
&lt;/h2&gt;

&lt;p&gt;Gap lock locks the gaps between index records, as well as the range before the first index record or after the last one. &lt;/p&gt;

&lt;p&gt;Example, InnoDB, RR: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;t(id PK, name KEY, sex, flag);&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are four records in the table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;li&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;
&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;
&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;huang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Query:&lt;br&gt;
&lt;/p&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;t&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;between&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;update&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This locks the gap, preventing other transactions from inserting, say, id=10.&lt;/p&gt;

&lt;p&gt;Purpose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoids “phantom reads” by locking non-existent rows.&lt;/li&gt;
&lt;li&gt;Only effective under REPEATABLE READ (RR).&lt;/li&gt;
&lt;li&gt;Automatically disabled under READ COMMITTED (RC).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next-Key Locks
&lt;/h2&gt;

&lt;p&gt;A Next-Key Lock is a combination of a Record Lock + Gap Lock. It locks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The indexed row itself.&lt;/li&gt;
&lt;li&gt;Including the index range.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;From the docs:&lt;br&gt;
If one session has a shared or exclusive lock on record R in an index, another session cannot insert a new index record in the gap immediately before R in the index order.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Example, InnoDB, RR:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;t(id PK, name KEY, sex, flag);&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;with records:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;li&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;
&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;
&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;huang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The potential next-key lock on the primary key is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;(-infinity, 1], (1, 3], (3, 5], (5, 9], (9, +infinity)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Purpose:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Also to prevent phantom reads, effective under RR, disabled under RC.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lock Type&lt;/th&gt;
&lt;th&gt;Level&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Blocking Behaviour&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Auto-Increment Lock&lt;/td&gt;
&lt;td&gt;Table&lt;/td&gt;
&lt;td&gt;Ensures sequential IDs for AUTO_INCREMENT&lt;/td&gt;
&lt;td&gt;Blocks concurrent inserts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shared/Exclusive Locks&lt;/td&gt;
&lt;td&gt;Row&lt;/td&gt;
&lt;td&gt;Controls read/write access&lt;/td&gt;
&lt;td&gt;Read-read OK, write conflicts blocked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intention Locks&lt;/td&gt;
&lt;td&gt;Table&lt;/td&gt;
&lt;td&gt;Signals future row-level lock intent&lt;/td&gt;
&lt;td&gt;Weak lock, enables compatibility checking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Insert Intention Locks&lt;/td&gt;
&lt;td&gt;Index Gap&lt;/td&gt;
&lt;td&gt;Allows safe concurrent inserts&lt;/td&gt;
&lt;td&gt;No blocking if insert positions differ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Record Locks&lt;/td&gt;
&lt;td&gt;Index Row&lt;/td&gt;
&lt;td&gt;Protects individual rows&lt;/td&gt;
&lt;td&gt;Blocks conflicting changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gap Locks&lt;/td&gt;
&lt;td&gt;Index Gap&lt;/td&gt;
&lt;td&gt;Prevents phantom inserts in range&lt;/td&gt;
&lt;td&gt;Active only under RR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Next-Key Locks&lt;/td&gt;
&lt;td&gt;Index Row+&lt;/td&gt;
&lt;td&gt;Combines record + gap lock for phantom prevention&lt;/td&gt;
&lt;td&gt;Active only under RR&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>mysql</category>
      <category>database</category>
    </item>
    <item>
      <title>PRIMARY KEY and UNIQUE Index Constraints and Their Strange Behaviors</title>
      <dc:creator>Guangyong</dc:creator>
      <pubDate>Mon, 24 Mar 2025 09:13:01 +0000</pubDate>
      <link>https://dev.to/yangguangyong/primary-key-and-unique-index-constraints-and-their-strange-behaviors-2k2k</link>
      <guid>https://dev.to/yangguangyong/primary-key-and-unique-index-constraints-and-their-strange-behaviors-2k2k</guid>
      <description>&lt;p&gt;The difference between MySQL's primary key constraint and unique index constraint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When Are Constraint Checks Triggered&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;MySQL checks constraints during two operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;insert&lt;/li&gt;
&lt;li&gt;update&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;If a constraint violation occurs, the behavior depends on the storage engine:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the storage engine supports transactions (like InnoDB), the SQL statement will automatically roll back.&lt;/li&gt;
&lt;li&gt;If the storage engine does not support transactions (like MyISAM), the SQL execution will be interrupted mid-way, potentially leaving the dataset in an unexpected partial state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example with InnoDB&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;primary&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;innodb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt; &lt;span class="k"&gt;values&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="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;t1&lt;/span&gt; &lt;span class="k"&gt;values&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second insert violates the primary key constraint, and InnoDB will roll back that SQL statement. Can check errors with:&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%2Fhuxq66kgxu7vpq0qej1m.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%2Fhuxq66kgxu7vpq0qej1m.png" alt="Image description" width="493" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example with MyISAM(The Tricky Part)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MyISAM&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt; &lt;span class="k"&gt;values&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="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt; &lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt; &lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt; &lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;update&lt;/span&gt; &lt;span class="n"&gt;t2&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&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;p&gt;What result set do you get after this update? It's &lt;strong&gt;2,5,6,10&lt;/strong&gt;. Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first row id=1 gets updated to 2 successfully.&lt;/li&gt;
&lt;li&gt;The second row id=5 attempts to become 6, but since id=6 already exists, this violates the UNIQUE constraint, so SQL execution stops, and this row isn’t modified.&lt;/li&gt;
&lt;li&gt;The third and fourth rows (id=6 and id=10) are not executed at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This partial update is some rows are updated, others fail silently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to Avoid This Mess?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use the InnoDB storage engine. InnoDB will roll back the entire &lt;strong&gt;update&lt;/strong&gt; if any constraint violation occurs — no partial updates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Handling Constraint Violations During INSERT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Can use the &lt;strong&gt;insert ... on duplicate key&lt;/strong&gt; syntax to specify what action to take if a primary key or unique constraint conflict occurs.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;t3&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="nb"&gt;char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="s1"&gt;'true'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MyISAM&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;t3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;values&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="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;t3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;t3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;t3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;t3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="n"&gt;duplicate&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="k"&gt;update&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'false'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The attempt to insert id=10 triggers a UNIQUE constraint violation.&lt;/li&gt;
&lt;li&gt;Instead of failing, it executes UPDATE flag='false' on the existing row where id=10.&lt;/li&gt;
&lt;li&gt;Effectively, this is the same as:
&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;t3&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'false'&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;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interestingly, the &lt;strong&gt;insert&lt;/strong&gt; statement returns:&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%2Ftynjv8tomc2zte6970ec.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%2Ftynjv8tomc2zte6970ec.png" alt="Image description" width="626" height="52"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Primary key and unique index constraints are checked on insert and update operations.&lt;/li&gt;
&lt;li&gt;InnoDB rolls back the entire SQL on constraint violations.&lt;/li&gt;
&lt;li&gt;MyISAM will partially execute and then stop on constraint violations, which may cause unexpected partial results.&lt;/li&gt;
&lt;li&gt;Can use insert ... on duplicate key update to define custom behavior when constraints are violated.&lt;/li&gt;
&lt;li&gt;Always use show warnings; to debug constraint-related errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;In high-concurrency, large-scale systems, for the sake of stability (and your sanity), always use InnoDB.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>database</category>
    </item>
    <item>
      <title>MQ: How Does It Achieve Peak Shaving and Valley Filling?</title>
      <dc:creator>Guangyong</dc:creator>
      <pubDate>Fri, 21 Mar 2025 01:33:30 +0000</pubDate>
      <link>https://dev.to/yangguangyong/mq-how-does-it-achieve-peak-shaving-and-valley-filling-jfp</link>
      <guid>https://dev.to/yangguangyong/mq-how-does-it-achieve-peak-shaving-and-valley-filling-jfp</guid>
      <description>&lt;p&gt;Message Queuing (MQ) has many application scenarios, such as message publishing and subscription, decoupling between upstream and downstream systems. One typical use of MQ is to buffer traffic, helping to shave peaks and fill valleys. &lt;/p&gt;

&lt;h1&gt;
  
  
  How do upstream and downstream systems usually communicate?
&lt;/h1&gt;

&lt;p&gt;There are two common communication methods:&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%2F9mg4sbbrp3xl6p38b9y4.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%2F9mg4sbbrp3xl6p38b9y4.png" alt="Image description" width="224" height="173"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Direct Call: Through an RPC framework, the upstream system directly calls the downstream system.&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%2F7tq09z6wxdzshzxrn5dv.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%2F7tq09z6wxdzshzxrn5dv.png" alt="Image description" width="465" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MQ Push: The upstream system sends messages to the MQ, and the MQ pushes the messages to the downstream system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Can these methods cache traffic or achieve peak shaving and valley filling?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No.&lt;/strong&gt; Whether using "direct calls" or "MQ push", both have a drawback: the downstream message receiver cannot control the traffic arriving at their system. If the upstream system doesn’t limit the speed, it could overwhelm the downstream system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Double 11 Shopping Festival Scenario
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Upstream system: Initiates the order placing operation.&lt;/li&gt;
&lt;li&gt;Downstream system: Completes the following business logic (inventory check, inventory freeze, balance check, balance freeze, order generation, balance deduction, inventory deduction, transaction generation, balance thaw, inventory thaw).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The upstream order placing operation is simple, sending 10,000 requests per second. The downstream logic is complex, processing only 2,000 requests per second. If the upstream system sends requests without throttling, it could overwhelm the downstream system, causing a system crash.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to prevent overwhelming the downstream system?
&lt;/h2&gt;

&lt;p&gt;To avoid the system crash, there are two common optimization strategies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buffering at the upstream queue, limiting the rate of requests sent.&lt;/li&gt;
&lt;li&gt;Buffering at the downstream queue, limiting the rate of execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, both solutions introduce additional business complexity. Any system requiring traffic buffering will need to incorporate similar mechanisms. This is a universal pain point that requires a generic solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can MQ Achieve Traffic Buffering?
&lt;/h2&gt;

&lt;p&gt;Yes, but it requires a small modification. To achieve traffic buffering with MQ, the MQ-server push mode can be upgraded to MQ-client pull mode. In this mode, the MQ-client, based on its processing capacity, pulls a batch of messages from the queue at regular intervals or in batches. The client then implements flow control, protecting itself from being overwhelmed. This is a generic feature provided by MQ, so no changes to the upstream or downstream systems are needed.&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%2F4205zeehj7zgy8ngkhbi.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%2F4205zeehj7zgy8ngkhbi.png" alt="Image description" width="469" height="176"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens if the Upstream System Sends Too Much Traffic?
&lt;/h2&gt;

&lt;p&gt;If the upstream system sends excessive traffic, the pull mode provided by MQ can indeed protect the downstream system by enabling it to pull messages at a controlled pace. But this raises the question: Will messages accumulate in the MQ queue?&lt;/p&gt;

&lt;p&gt;In pull mode, the downstream MQ-client can fetch messages in batches. However, to maximize throughput, the downstream system needs to be optimized. For example, batch writes can be used to improve processing efficiency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;MQ-client pull mode enables periodic or batch message pulling, which helps smooth out traffic, offering self-protection for the downstream system (this is the job of MQ).&lt;/li&gt;
&lt;li&gt;To increase overall throughput, the downstream system must implement optimizations such as batch processing (this is the job of the message receiver).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why can't refunds be processed on Double 11? Because for the entire transaction process, only the first half is completed. The second half, involving the MQ, is still stored in the database, waiting for the downstream systems to process it.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
    </item>
    <item>
      <title>InnoDB Indexs</title>
      <dc:creator>Guangyong</dc:creator>
      <pubDate>Thu, 20 Mar 2025 09:00:09 +0000</pubDate>
      <link>https://dev.to/yangguangyong/innodb-indexs-gmd</link>
      <guid>https://dev.to/yangguangyong/innodb-indexs-gmd</guid>
      <description>&lt;p&gt;Database indexes are divided into Primary Indexe and Secondary Indexe. How do InnoDB and MyISAM utilize B+ trees to implement these two types of indexes, and what are the differences between them?&lt;/p&gt;

&lt;h1&gt;
  
  
  Question 1: What is the index structure of MyISAM?
&lt;/h1&gt;

&lt;p&gt;In MyISAM, the index structure is separate from the data rows, meaning it uses what is called a non-clustered index. The primary index and secondary index in MyISAM don’t have any significant differences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is a contiguous storage region for row records.&lt;/li&gt;
&lt;li&gt;In a primary index, the leaf nodes store the primary key along with the corresponding row record pointer.&lt;/li&gt;
&lt;li&gt;In a secondary index, the leaf nodes store the indexed column and a pointer to the corresponding row record.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note: MyISAM tables don’t necessarily require a primary key.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The primary and secondary indexes are two independent B+ trees. When you perform a search using an indexed column, the system first locates the leaf node in the B+ tree, then uses the pointer to find the corresponding row record.&lt;/p&gt;

&lt;p&gt;For example, consider the table &lt;code&gt;t(id PK, name KEY, sex, flag)&lt;/code&gt;; which contains four records:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1, joe, m, A
3, bob, m, A
5, king, m, A
9, shiho, f, B
&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%2Fdfh8g5tg0whcgdoek3nq.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%2Fdfh8g5tg0whcgdoek3nq.png" alt="Image description" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The B+ tree indexing structure looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Row records are stored separately.&lt;/li&gt;
&lt;li&gt;id is the PK, with an index tree for id, and the leaf points to the row record.&lt;/li&gt;
&lt;li&gt;name is a KEY, with an index tree for name, and the leaf also points to the row record.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Question 2: What is the index structure of InnoDB?
&lt;/h1&gt;

&lt;p&gt;In InnoDB, the primary index and row records are stored together, which is why it's called a clustered index:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is no separate area for storing row records.&lt;/li&gt;
&lt;li&gt;In a primary index, the leaf nodes store the primary key and the row record itself (not just the pointer).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note: This is why InnoDB’s primary key queries are very fast.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because of this structure, InnoDB tables must have a clustered index:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If a table defines a primary key, the primary key becomes the clustered index.&lt;/li&gt;
&lt;li&gt;If there is no primary key, the first non-null unique column is used as the clustered index.&lt;/li&gt;
&lt;li&gt;If there is no unique column, InnoDB creates a hidden row-id as the clustered index.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can only have one clustered index in InnoDB, because row data can only be physically stored once on the disk.&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%2Fuauglmz77i9zshjzaaox.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%2Fuauglmz77i9zshjzaaox.png" alt="Image description" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;InnoDB’s secondary indexes can be multiple. They differ from the clustered index:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The leaf nodes of a secondary index store the primary key (not just a pointer).&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Question 3: Why does InnoDB recommend using a progressively increasing primary key?
&lt;/h1&gt;

&lt;p&gt;In InnoDB, since row data and indexes are combined, using a progressively increasing primary key avoids index fragmentation during inserts, preventing excessive row movement in the index.&lt;/p&gt;




&lt;h1&gt;
  
  
  Question 4: Why is it not recommended to use long columns as primary keys in InnoDB?
&lt;/h1&gt;

&lt;p&gt;Let’s consider a scenario where you have a user center that includes fields like ID card number, MD5 hash of ID card, name, birth date, etc. These fields are queried frequently and require transactional support, so you must use the InnoDB storage engine.&lt;/p&gt;

&lt;p&gt;What’s the best way to design the data table? A simple design would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user(id_code PK, id_md5(index), name(index), birthday(index));
&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%2Fwl7v81hpdmgre91nwqap.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%2Fwl7v81hpdmgre91nwqap.png" alt="Image description" width="494" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, the index tree and record structure looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;id_code as a clustered index, pointing to the row records.&lt;/li&gt;
&lt;li&gt;Other indexes store id_code values.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since id_code (ID card number) is a long string, every index needs to store this value. When you have a large dataset and limited memory, MySQL's buffer pool will store fewer indexes and row data, increasing the chance of disk I/O.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: This also increases the disk space used by the indexes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A better solution is to add an auto-increment id column with no business meaning as the primary key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user(id PK auto inc, id_code(index), id_md5(index), name(index), birthday(index));
&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%2Fx2lsspsflpllt8sljs0j.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%2Fx2lsspsflpllt8sljs0j.png" alt="Image description" width="570" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This way, the buffer pool can store more indexes and row data, reducing disk I/O frequency and improving overall performance.&lt;/p&gt;




&lt;h1&gt;
  
  
  Question 5: What potential problem arises from InnoDB's secondary index storing the primary key value?
&lt;/h1&gt;

&lt;p&gt;When using a secondary index in InnoDB, you might encounter a problem called “covering index”, or “back-to-table queries”.&lt;/p&gt;

&lt;p&gt;What are back-to-table queries? Let’s use the earlier example:&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;t(id PK, name KEY, sex, flag);&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The id column is the clustered index (PK), and the leaf nodes store row records.&lt;/li&gt;
&lt;li&gt;The name column is a secondary index, and its leaf nodes store the primary key (id).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since the secondary index does not point directly to the row record, we must scan the index twice to get the data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, we locate the primary key value (e.g., id=5) in the secondary index.&lt;/li&gt;
&lt;li&gt;Then, we use the primary key to find the corresponding row record in the clustered index.&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%2Fvfodz5ngz7rhhhruqvmb.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%2Fvfodz5ngz7rhhhruqvmb.png" alt="Image description" width="800" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is known as a back-to-table query. It’s slower than scanning a single index tree. Example query:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SELECT id, name, sex FROM t WHERE name='bob';&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;The process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, scan the secondary index to get the primary key id=5.&lt;/li&gt;
&lt;li&gt;Then, scan the primary index to retrieve the actual row.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This process is slower than just scanning the index tree once.&lt;/p&gt;




&lt;h1&gt;
  
  
  Question 6: How to optimize back-to-table queries?
&lt;/h1&gt;

&lt;p&gt;The common solution is to use covering indexes. What is a covering index?&lt;/p&gt;

&lt;p&gt;According to the SQL Server documentation:&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%2Fk6t8cnkje8sj79na5dqt.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%2Fk6t8cnkje8sj79na5dqt.png" alt="Image description" width="800" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;According to the SQL Server documentation (also applicable to MySQL), a covering index allows you to retrieve all the required data from a single index without needing to go back to the table.&lt;/p&gt;

&lt;p&gt;To implement a covering index, you can create a composite index that includes all the columns used in the query. For example, instead of using a single column index on name, you can upgrade it to a composite 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_sex on t(name, sex);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, 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 id, name, sex from t where name='bob';

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Can be handled by the covering index, avoiding the need to go back to the table, thus improving performance.&lt;/p&gt;

</description>
      <category>mysql</category>
      <category>database</category>
    </item>
    <item>
      <title>Database Indexes: Why and How?</title>
      <dc:creator>Guangyong</dc:creator>
      <pubDate>Wed, 19 Mar 2025 10:39:04 +0000</pubDate>
      <link>https://dev.to/yangguangyong/database-indexes-why-and-how-2ikc</link>
      <guid>https://dev.to/yangguangyong/database-indexes-why-and-how-2ikc</guid>
      <description>&lt;h1&gt;
  
  
  Question 1: Why Do We Need Indexes in a Database?
&lt;/h1&gt;

&lt;p&gt;Imagine a library with 10 million books, and you need to find The Road to Architect. If you check each book one by one, how long would that take? Instead, librarians have a system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;History books are on the first floor, literature on the second, IT books on the third…&lt;/li&gt;
&lt;li&gt;IT books are further divided into software and hardware…&lt;/li&gt;
&lt;li&gt;Software books are sorted alphabetically…&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This way, finding a book becomes much faster. Similarly, when a database stores 10 million records and you need to find name="Architect", scanning one by one would be painfully slow. That's why we use indexes to speed up lookups.&lt;/p&gt;

&lt;h1&gt;
  
  
  Question 2: Hash vs. Tree-Why Use a Tree Structure for Indexes?
&lt;/h1&gt;

&lt;p&gt;There are two common data structures used to speed up lookups:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hashing (e.g., HashMap)-Average time complexity for search/insert/update/delete is O(1).&lt;/li&gt;
&lt;li&gt;Tree structures (e.g., balanced binary search trees)-Average time complexity for operations is O(log(n)).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Clearly, a hash-based index is faster than a tree-based index. So why do databases still prefer tree-based indexes?&lt;/p&gt;

&lt;p&gt;It all comes down to SQL query requirements.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you only need single record lookups, like SELECT * FROM t WHERE name="Architect";, hash indexes are indeed the best choice.&lt;/li&gt;
&lt;li&gt;However, for sorted queries, such as: GROUP BY, ORDER BY and Range comparisons (&amp;lt;, &amp;gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A hash index becomes inefficient, degrading to O(n) complexity. On the other hand, tree structures retain O(log(n)) efficiency due to their ordered nature.&lt;/p&gt;

&lt;p&gt;Key takeaway: Database indexes must be designed to meet query patterns, not just raw performance metrics.&lt;/p&gt;

&lt;p&gt;Also, note that InnoDB doesn't support manually created hash indexes. Instead, it has an adaptive hash index, which is managed automatically by the database engine.&lt;/p&gt;

&lt;h1&gt;
  
  
  Question 3: Why Do Databases Use B+ Trees for Indexes?
&lt;/h1&gt;

&lt;p&gt;To understand why, let's first look at some tree structures.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Binary Search Tree (BST)&lt;/li&gt;
&lt;/ol&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%2F9z9u86ou6tj2ghn37nyw.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%2F9z9u86ou6tj2ghn37nyw.png" alt="Image description" width="800" height="629"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A BST is a simple and well-known data structure, but it's not suitable for database indexing because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As the dataset grows, the tree height increases, making searches slower.&lt;/li&gt;
&lt;li&gt;Each node stores only one record, leading to excessive disk I/O.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;B-Tree&lt;/li&gt;
&lt;/ol&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%2Fhfqob6xtmhlcbuvcsns1.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%2Fhfqob6xtmhlcbuvcsns1.png" alt="Image description" width="800" height="554"&gt;&lt;/a&gt;&lt;br&gt;
B-Tree improve on BST:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instead of binary splits, they use m-way branching.&lt;/li&gt;
&lt;li&gt;Both leaf and non-leaf nodes store data.&lt;/li&gt;
&lt;li&gt;You can retrieve all records using in-order traversal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key advantage of B-Trees is their efficient use of the locality principle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Memory is fast, but disk reads are slow.&lt;/li&gt;
&lt;li&gt;Disk prefetching means data is read in pages (e.g., 4KB per page in OS, 16KB in MySQL).&lt;/li&gt;
&lt;li&gt;Locality principle: If a program accesses data, it's likely to access nearby data soon.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since B-Trees store multiple records per node, they reduce the number of disk I/O operations, making lookups faster.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;B+Tree&lt;/li&gt;
&lt;/ol&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%2Ffin0qlpqu5mgd5dpg67o.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%2Ffin0qlpqu5mgd5dpg67o.png" alt="Image description" width="800" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The B+ Tree is an enhancement of the B-Tree:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Non-leaf nodes do not store actual data-only keys.&lt;/li&gt;
&lt;li&gt;All data is stored in leaf nodes at the same level.&lt;/li&gt;
&lt;li&gt;Leaf nodes are linked, allowing for fast range queries without in-order traversal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why is B+ Tree better?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster range queries-Find min and max, then traverse the linked list.&lt;/li&gt;
&lt;li&gt;More compact indexing-Non-leaf nodes store only keys, making the index more memory-efficient.&lt;/li&gt;
&lt;li&gt;Lower tree height-With m-way branching, B+ Trees have much lower depth than BSTs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  How Does B+ Tree Reduce Tree Depth?
&lt;/h1&gt;

&lt;p&gt;Let's estimate:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Assume each node is 4KB.&lt;/li&gt;
&lt;li&gt;A key size is 8 bytes, so one node can store 500 keys.&lt;/li&gt;
&lt;li&gt;The tree has an m-way branching factor of ~1000.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tree Level&lt;/th&gt;
&lt;th&gt;Nodes&lt;/th&gt;
&lt;th&gt;Total Keys&lt;/th&gt;
&lt;th&gt;Approx Size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Row 1 500&lt;/td&gt;
&lt;td&gt;4KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;500000&lt;/td&gt;
&lt;td&gt;4MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;1000000&lt;/td&gt;
&lt;td&gt;500M&lt;/td&gt;
&lt;td&gt;4GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;With just 3 levels, a B+ Tree can handle 500 million records while keeping the index small (~4GB). This makes it an excellent choice for large databases.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;Indexes accelerate database queries.&lt;/li&gt;
&lt;li&gt;Hash indexes (O(1)) are faster for lookups, but tree indexes (O(log(n))) are better for range queries.&lt;/li&gt;
&lt;li&gt;InnoDB does not support manual hash indexes but uses adaptive hash indexing.&lt;/li&gt;
&lt;li&gt;Disk prefetching and locality principles make B-Trees highly efficient for database indexing.&lt;/li&gt;
&lt;li&gt;B+ Trees outperform B-Trees because they:

&lt;ol&gt;
&lt;li&gt;Have faster range queries due to leaf node links.&lt;/li&gt;
&lt;li&gt;Store actual data only in leaf nodes, optimizing memory usage.&lt;/li&gt;
&lt;li&gt;Have lower depth, enabling faster lookups and less disk I/O.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;The B+ Tree is the standard for database indexing because it balances efficiency, scalability, and query flexibility.&lt;/p&gt;

</description>
      <category>database</category>
      <category>mysql</category>
    </item>
  </channel>
</rss>
