<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
        <title>Jungle&#39;s Blog</title>
        <link>https://Jungle430.github.io/</link>
        <description>Welcome to Jungle&#39;s blog.</description>
        <generator>Hugo -- gohugo.io</generator><language>zh-CN</language><managingEditor>junglece430@gmail.com (Jungle)</managingEditor>
            <webMaster>junglece430@gmail.com (Jungle)</webMaster><lastBuildDate>Sat, 24 Aug 2024 21:18:50 &#43;0800</lastBuildDate>
            <atom:link href="https://Jungle430.github.io/index.xml" rel="self" type="application/rss+xml" />
        <item>
    <title>What is LSM, and Why LSM?</title>
    <link>https://Jungle430.github.io/posts/mini-lsm/introduction/</link>
    <pubDate>Sat, 24 Aug 2024 21:18:50 &#43;0800</pubDate><author>junglece430@gmail.com (Jungle)</author><guid>https://Jungle430.github.io/posts/mini-lsm/introduction/</guid>
    <description><![CDATA[<h2 id="what-is-lsm-and-why-lsm">What is LSM, and Why LSM?</h2>
<ul>
<li>
<p>本文章是对LSM的基本介绍</p>
</li>
<li>
<p>LSM trees全称为Log-structured merge trees，是一种用于KV存储引擎的数据结构，它被广泛应用于分布式存储系统</p>
</li>
<li>
<p>使用其的工业产品</p>
<ul>
<li><a href="https://www.pingcap.com/" target="_blank" rel="noopener noreffer">TiDB</a> and <a href="https://www.cockroachlabs.com/" target="_blank" rel="noopener noreffer">CockroachDB</a></li>
<li><a href="http://rocksdb.org/" target="_blank" rel="noopener noreffer">RocksDB</a>, based on <a href="https://github.com/google/leveldb" target="_blank" rel="noopener noreffer">LevelDB</a></li>
</ul>
</li>
<li>
<p>LSM tree是一种append-friendly data structure，和其他的KV存储引擎底层的数据结构，比如RB-Tree and B-Tree最大的不同就是当更改数据的时候，RB-Tree and B-Tree需要在内存或者磁盘把原有数据进行修改，但是对于LSM tree来说上面的修改操作从之前的同步操作改成了lazily applied to the storage，引擎可以一次性批量将前面修改数据的操作处理成SST (sorted string table) files，然后再将其写入磁盘（这个处理的速度要比前面的RB-Tree and B-Tree快得多，顺序追加日志要比查找到值再改快得多），一旦写入磁盘，引擎将不再直接修改它们，只需要后台的任务定时将以进行compaction即可</p>
</li>
<li>
<p>这种架构上的设计让LSM trees易于使用</p>
<ul>
<li>数据在持久存储里面是不可变的，并发控制的问题因为这个变得简单，而且compaction的任务可以交给远程的服务器去做，这样的架构也非常适合现在的云原生（存储和compaction完全可以派发给不同的机器）</li>
<li>引擎的读和写的性能可以通过调整compaction算法/算法的参数来进行变化，这样可以让引擎适应多种不同的情境</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>
<figure><a class="lightgallery" href="/img/mini-lsm/lsm-structure.jpeg" title="/img/mini-lsm/lsm-structure.jpeg" data-thumbnail="/img/mini-lsm/lsm-structure.jpeg" data-sub-html="<h2>lsm-structure</h2>">
        
    </a><figcaption class="image-caption">lsm-structure</figcaption>
    </figure>
</li>
<li>
<p>一个LSM存储引擎大致可以分为下面三个部分</p>
<ul>
<li>Write-ahead log to persist temporary data for recovery.</li>
<li>SSTs on the disk to maintain an LSM-tree structure.</li>
<li>Mem-tables in memory for batching small writes.</li>
</ul>
</li>
<li>
<p>一个存储引擎应该提供下面四个接口</p>
<ul>
<li><code>Put(key, value)</code>: store a key-value pair in the LSM tree.</li>
<li><code>Delete(key)</code>: remove a key and its corresponding value.</li>
<li><code>Get(key)</code>: get the value corresponding to a key.</li>
<li><code>Scan(range)</code>: get a range of key-value pairs.</li>
</ul>
</li>
<li>
<p>为了保证持久化还会有一个接口</p>
<ul>
<li><code>Sync()</code>: ensure all the operations before <code>sync</code> are persisted to the disk.</li>
</ul>
</li>
<li>
<p>一些引擎会将<code>Put</code>和<code>Write</code>的操作组合起来处理，称为<code>WriteBatch</code></p>
</li>
<li>
<p>本教程中LSM的压缩算法选用leveled compaction algorithm，在工业界也很常用</p>
</li>
</ul>
<hr>
<ul>
<li>Write Path
<figure><a class="lightgallery" href="/img/mini-lsm/write-path.jpeg" title="/img/mini-lsm/write-path.jpeg" data-thumbnail="/img/mini-lsm/write-path.jpeg" data-sub-html="<h2>write-path</h2>">
        
    </a><figcaption class="image-caption">write-path</figcaption>
    </figure></li>
<li>The write path of LSM contains four steps:
<ul>
<li>Write the key-value pair to the write-ahead log so that it can be recovered after the storage engine crashes.</li>
<li>Write the key-value pair to memtable. After (1) and (2) are completed, we can notify the user that the write operation is completed.</li>
<li>(In the background) When a mem-table is full, we will freeze them into immutable mem-tables and flush them to the disk as SST files in the background.</li>
<li>(In the background) The engine will compact some files in some levels into lower levels to maintain a good shape for the LSM tree so that the read amplification is low.</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>
<p>Read Path
<figure><a class="lightgallery" href="/img/mini-lsm/read-path.jpeg" title="/img/mini-lsm/read-path.jpeg" data-thumbnail="/img/mini-lsm/read-path.jpeg" data-sub-html="<h2>read-path</h2>">
        
    </a><figcaption class="image-caption">read-path</figcaption>
    </figure></p>
</li>
<li>
<p>When we want to read a key</p>
<ul>
<li>We will first probe all the mem-tables from the latest to the oldest.</li>
<li>If the key is not found, we will then search the entire LSM tree containing SSTs to find the data.</li>
</ul>
</li>
</ul>
]]></description>
</item>
<item>
    <title>数据库SQL引擎基础(OceanBase-MiniOB)</title>
    <link>https://Jungle430.github.io/posts/database/the_foundation_of_the_database_sql_engine/</link>
    <pubDate>Sun, 21 Jul 2024 01:18:11 &#43;0800</pubDate><author>junglece430@gmail.com (Jungle)</author><guid>https://Jungle430.github.io/posts/database/the_foundation_of_the_database_sql_engine/</guid>
    <description><![CDATA[<h1 id="数据库sql引擎基础oceanbase-miniob">数据库SQL引擎基础$(OceanBase-MiniOB)$</h1>
<h2 id="引擎架构概览">引擎架构概览</h2>
<ul>
<li>
<figure><a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img1.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img1.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img1.png" data-sub-html="<h2>MySQL的引擎架构（红框）</h2>">
        
    </a><figcaption class="image-caption">MySQL的引擎架构（红框）</figcaption>
    </figure>
</li>
<li>
<figure><a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img2.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img2.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img2.png" data-sub-html="<h2>OceanBase引擎架构</h2>">
        
    </a><figcaption class="image-caption">OceanBase引擎架构</figcaption>
    </figure>
</li>
<li>
<p>一条SQL语句的常见结构</p>
</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="n">XXX</span><span class="w"> </span><span class="p">(</span><span class="mi">7</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="n">XXX</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">JOIN</span><span class="w"> </span><span class="n">XXX</span><span class="w"> </span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">ON</span><span class="w"> </span><span class="n">XXX</span><span class="w"> </span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">WHERE</span><span class="w"> </span><span class="n">XXX</span><span class="w"> </span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">GROUP</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">XXX</span><span class="w"> </span><span class="p">(</span><span class="mi">5</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">HAVING</span><span class="w"> </span><span class="n">XXX</span><span class="w"> </span><span class="p">(</span><span class="mi">6</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">XXX</span><span class="w"> </span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">LIMIT</span><span class="w"> </span><span class="n">XXX</span><span class="w"> </span><span class="p">(</span><span class="mi">9</span><span class="p">)</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><h2 id="解析--执行sql">解析 &amp; 执行SQL</h2>
<h3 id="parser">Parser</h3>
<ul>
<li><figure><a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img3.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img3.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img3.png" data-sub-html="<h2>将SQL转化为数据库能识别的数据结构</h2>">
        
    </a><figcaption class="image-caption">将SQL转化为数据库能识别的数据结构</figcaption>
    </figure></li>
</ul>
<h3 id="resolver">Resolver</h3>
<ul>
<li><a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img4.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img4.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img4.png">
        
    </a></li>
<li><figure><a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img5.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img5.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img5.png" data-sub-html="<h2>同时也会将SQL转化为一个新的数据工程性的数据结构</h2>">
        
    </a><figcaption class="image-caption">同时也会将SQL转化为一个新的数据工程性的数据结构</figcaption>
    </figure></li>
</ul>
<h3 id="transformer--optimizer">Transformer &amp; Optimizer</h3>
<ul>
<li>在这两层主要是要把上一层的结构转化为火山模型中的“算子树（自己造的词，方便理解）”，同时对查询计划进行优化</li>
<li><figure><a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img6.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img6.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img6.png" data-sub-html="<h2>生成查询计划</h2>">
        
    </a><figcaption class="image-caption">生成查询计划</figcaption>
    </figure></li>
<li><figure><a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img7.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img7.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img7.png" data-sub-html="<h2>优化查询计划</h2>">
        
    </a><figcaption class="image-caption">优化查询计划</figcaption>
    </figure></li>
<li><figure><a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img8.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img8.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img8.png" data-sub-html="<h2>OceanBase的优化计划部分</h2>">
        
    </a><figcaption class="image-caption">OceanBase的优化计划部分</figcaption>
    </figure></li>
</ul>
<h3 id="executor">Executor</h3>
<ul>
<li>
<p>常见的就是火山模型</p>
</li>
<li>
<p>所有的代数运算都被看成了operator（也就是图里面的一个节点）</p>
</li>
<li>
<p>每一层的operator都将下一层的operator看成一张表，每次调用next()都是获取表中的一张数据</p>
</li>
<li>
<p>优点：简单，让查询计划变得富有弹性，使其便于优化</p>
</li>
<li>
<p>缺点：大量的虚函数调用，流水线模型的破坏，不能让CPU乱序执行带来的效率低下（但是这个模型在90年代诞生，当时I/O的问题远比CPU的问题要重要的多）</p>
</li>
<li>
<p>关于火山模型的问题和向量化|类JIT代码动态编译/生成，比较好的两篇文章，读完收获很大</p>
<ul>
<li><a href="https://zhuanlan.zhihu.com/p/587568943" target="_blank" rel="noopener noreffer">为什么需要向量化执行引擎</a></li>
<li><a href="https://zhuanlan.zhihu.com/p/100933389" target="_blank" rel="noopener noreffer">数据库计算引擎的优化技术：向量化执行与代码生成</a></li>
</ul>
</li>
<li>
<p>其他优化的点</p>
<ul>
<li>操作符融合：比如把Scan和Fillter融合在一块执行</li>
<li>拉取模型和推送模型：火山模型中应该是上层的算子来进行推动，但是推送模型希望是下面的算子往上推，而不是从上面拉取</li>
</ul>
</li>
<li>
<a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img9.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img9.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img9.png">
        
    </a>
</li>
<li>
<figure><a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img10.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img10.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img10.png" data-sub-html="<h2>下推引擎中，下层的operator拿到了上层的要求后直接带着要求返回结果，而不是想上拉引擎那样只是傻傻的返回tuple</h2>">
        
    </a><figcaption class="image-caption">下推引擎中，下层的operator拿到了上层的要求后直接带着要求返回结果，而不是想上拉引擎那样只是傻傻的返回tuple</figcaption>
    </figure>
</li>
</ul>
<h3 id="fast-parser--plan-cache">Fast Parser &amp; Plan Cache</h3>
<ul>
<li>
<figure><a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img11.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img11.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img11.png" data-sub-html="<h2>把之前SQL解析出来的Plan给进行缓存，这样就可以避免大的，频繁调用的SQL不停的被解析造成的效率低下</h2>">
        
    </a><figcaption class="image-caption">把之前SQL解析出来的Plan给进行缓存，这样就可以避免大的，频繁调用的SQL不停的被解析造成的效率低下</figcaption>
    </figure>
</li>
<li>
<p>OceanBase的优化：SQL可以先找到和自己相似的SQL进行数值上的替换，这样自己的查询计划也就出来了</p>
</li>
</ul>
<h2 id="常见名词">常见名词</h2>
<ul>
<li>一个高效的SQL有很多考虑因素
<ul>
<li>disk</li>
<li>memory</li>
<li>cpu</li>
<li>SQL计划是否更优，选择的算法是否合理</li>
</ul>
</li>
</ul>
<h2 id="基础关系代数符号--优化操作">基础关系代数符号 &amp; 优化操作</h2>
<ul>
<li>
<a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img12.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img12.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img12.png">
        
    </a>
</li>
<li>
<a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img13.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img13.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img13.png">
        
    </a>
</li>
<li>
<a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img14.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img14.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img14.png">
        
    </a>
</li>
<li>
<p>相关文章</p>
<ul>
<li><a href="https://jungle430.github.io/posts/cmu-15-445-database-systems/chapter11/" target="_blank" rel="noopener noreffer">CMU 15-445 Lecture #11: Joins Algorithms</a></li>
<li><a href="https://open.oceanbase.com/blog/10900347" target="_blank" rel="noopener noreffer">SQL 改写系列九：外连接转内连接的常见场景与错误</a></li>
</ul>
</li>
<li>
<a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img15.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img15.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img15.png">
        
    </a>
</li>
<li>
<a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img16.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img16.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img16.png">
        
    </a>
</li>
</ul>
<h2 id="关系表达式的等价规则转换当成工具字典就行">关系表达式的等价规则转换（当成工具字典就行）</h2>
<ul>
<li>
<a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img17.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img17.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img17.png">
        
    </a>
</li>
<li>
<a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img18.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img18.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img18.png">
        
    </a>
</li>
<li>
<figure><a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img19.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img19.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img19.png" data-sub-html="<h2>运算律优化的例子，选择下推，连接变小</h2>">
        
    </a><figcaption class="image-caption">运算律优化的例子，选择下推，连接变小</figcaption>
    </figure>
</li>
<li>
<p>由于连接有交换律，根据排列组合，极少的连接就会造出来非常多的计划，但是实际上数据库不可能挨个去算每个计划的代价</p>
</li>
<li>
<p>Interesting sort order(如果前面连接出来的结果有序，那么后面优先选择有序的表进行连接，这样可以使用sorted join来加快顺序)</p>
</li>
</ul>
<h2 id="左深树">左深树</h2>
<ul>
<li>根据前面的优化，左深树比右深树更有优势</li>
</ul>
<h2 id="启发式规则">启发式规则</h2>
<ul>
<li>
<p>多年经验和论文总结而成</p>
</li>
<li>
<a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img20.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img20.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img20.png">
        
    </a>
</li>
</ul>
<h2 id="统计信息">统计信息</h2>
<ul>
<li>
<a class="lightgallery" href="/img/DataBase/The_foundation_of_the_database_SQL_engine/img21.png" title="/img/DataBase/The_foundation_of_the_database_SQL_engine/img21.png" data-thumbnail="/img/DataBase/The_foundation_of_the_database_SQL_engine/img21.png">
        
    </a>
</li>
<li>
<p>根据选择率和基数和基数来决定是否使用索引还是用全表（不一定索引比全表扫描强，比如sex这种列）</p>
</li>
</ul>
<h2 id="尾巴">尾巴</h2>
<ul>
<li>留一篇文章下周工位摸鱼读（又该申请权限力）
<ul>
<li><a href="https://link.zhihu.com/?target=https%3A//cn.pingcap.com/blog/tidb-source-code-reading-7" target="_blank" rel="noopener noreffer">TiDB 源码阅读系列文章（七）基于规则的优化 | PingCAP</a></li>
</ul>
</li>
<li>写到445的Lab3感觉需要拓展的知识点开始变得异常的多（因为这部分本身的比较广泛，前面的bpm和hash index都比较窄和单一），实验指导书看了一半就附带被推动着看了好几篇有关火山模型和向量化处理的文章（主要是工位上只能看这些，知乎那两篇确实质量很高，看完收获很大），和之前在牛客上认识，现在在2012实验室做db的朋友摸鱼聊天，看他解决bug的同时发现指令流水线，内存对齐，编译链接，并行计算这些计算机架构|操作系统的知识其实在这种底层的领域会不停的碰到，有一个扎实的基础会加快你发现bug原因的速度，看来当时的量化方法，csapp的知识不能再吃灰了，有时间还是得补一下自己的基础</li>
</ul>
]]></description>
</item>
<item>
    <title>CMU 15-445 Lecture #24: Distributed OLAP Databases</title>
    <link>https://Jungle430.github.io/posts/cmu-15-445-database-systems/chapter24/</link>
    <pubDate>Tue, 18 Jun 2024 09:58:42 &#43;0800</pubDate><author>junglece430@gmail.com (Jungle)</author><guid>https://Jungle430.github.io/posts/cmu-15-445-database-systems/chapter24/</guid>
    <description><![CDATA[<h1 id="cmu-15-445-database-systems">CMU 15-445 Database Systems</h1>
<h2 id="lecture-24-distributed-olap-databases">Lecture #24: Distributed OLAP Databases</h2>
<h3 id="decision-support-systems"><strong>Decision Support Systems</strong></h3>
<ul>
<li>
<p>OLAP其他称呼，就是分析数据进行公司的决策分析的</p>
</li>
<li>
<p>两种“数据”架构</p>
<ul>
<li><strong>Star Schema</strong></li>
<li><strong>Snowflake Schema</strong></li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>
<p><strong>Star Schema</strong></p>
<ul>
<li>
<p>一张核心表，通过外键连接到外面的表</p>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter24-1.png" title="/img/CMU 15-445 Database Systems/chapter24-1.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter24-1.png" data-sub-html="<h2>下面两个字段是核心字段，上面的用来连接其他表的</h2>">
        
    </a><figcaption class="image-caption">下面两个字段是核心字段，上面的用来连接其他表的</figcaption>
    </figure>
</li>
<li>
<p>一个中心，多个描述</p>
</li>
<li>
<p>缺点：部分枚举本来可以用数字+映射表示，在这个架构里面必须写真实属性，造成了数据冗余</p>
</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>
<p><strong>Snowflake Schema</strong></p>
<ul>
<li>
<p>外面的一层还可以向外拓展，解决了上面数据冗余的问题</p>
</li>
<li>
<a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter24-2.png" title="/img/CMU 15-445 Database Systems/chapter24-2.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter24-2.png">
        
    </a>
</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>对比
<ul>
<li>雪花型更省空间，而且避免了规范化的问题（前面星型的枚举人们可能用不同的词汇描述，比如一个人记low，另一个记bad）</li>
<li>雪花型的查询更复杂，跑的会更慢</li>
</ul>
</li>
</ul>
<h3 id="execution-models"><strong>Execution Models</strong></h3>
<ul>
<li>
<p><strong>PUSH QUERY TO DATA</strong></p>
<ul>
<li><figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter24-4.png" title="/img/CMU 15-445 Database Systems/chapter24-4.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter24-4.png" data-sub-html="<h2>将查询计划分给网关节点，网关节点根据查询内容和数据分布的情况向其他节点分配查询计划，每一个节点尽力执行查询计划然后将结果返回给应用</h2>">
        
    </a><figcaption class="image-caption">将查询计划分给网关节点，网关节点根据查询内容和数据分布的情况向其他节点分配查询计划，每一个节点尽力执行查询计划然后将结果返回给应用</figcaption>
    </figure></li>
</ul>
</li>
<li>
<p><strong>PULL DATA TO QUERY</strong></p>
<ul>
<li><figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter24-3.png" title="/img/CMU 15-445 Database Systems/chapter24-3.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter24-3.png" data-sub-html="<h2>数据不在本地，如果我需要执行查询的话必须要把数据加载到本地（放在shared disk架构里面就是把页拉到自己本地）</h2>">
        
    </a><figcaption class="image-caption">数据不在本地，如果我需要执行查询的话必须要把数据加载到本地（放在shared disk架构里面就是把页拉到自己本地）</figcaption>
    </figure></li>
</ul>
</li>
</ul>
<h3 id="query-planning"><strong>Query Planning</strong></h3>
<ul>
<li>
<p><strong>Physical Operators</strong></p>
<ul>
<li>把查询计划切成一个个得小块推送到对应的数据节点上面去，常用的方案</li>
</ul>
</li>
<li>
<p><strong>SQL</strong></p>
<ul>
<li>切的是SQL语句</li>
<li><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter24-5.png" title="/img/CMU 15-445 Database Systems/chapter24-5.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter24-5.png">
        
    </a></li>
</ul>
</li>
</ul>
<h3 id="distributed-join-algorithms"><strong>Distributed Join Algorithms</strong></h3>
<ul>
<li>把可以JOIN的部分集中到一个节点JOIN</li>
</ul>
<h3 id="cloud-systems"><strong>Cloud Systems</strong></h3>
<ul>
<li>Newer systems are starting to blur the lines between shared-nothing and shared-disk.
<ul>
<li>Example: You can do simple filtering on Amazon S3 before copying data to compute nodes.</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>
<p><strong>Managed DBMSs</strong></p>
<ul>
<li>数据库软件还是那个软件，但实际上是虚拟机+软件（腾讯/阿里云的数据库就是这样，帮你托管数据库）</li>
<li>便宜，易转型（从本地MySQL转到云数据库）</li>
</ul>
</li>
<li>
<p><strong>Cloud-Native DBMSs</strong></p>
<ul>
<li>就是为了在云上运行设计的</li>
</ul>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter24-6.png" title="/img/CMU 15-445 Database Systems/chapter24-6.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter24-6.png" data-sub-html="<h2>shared disk可以动态分配计算资源</h2>">
        
    </a><figcaption class="image-caption">shared disk可以动态分配计算资源</figcaption>
    </figure>
</li>
<li>
<p>云数据库也有人希望把不同厂家的组件组装起来来一个新的，主要是希望统一文件格式，但是太难。。。</p>
</li>
</ul>
]]></description>
</item>
<item>
    <title>CMU 15-445 Lecture #23: Distributed OLTP Databases</title>
    <link>https://Jungle430.github.io/posts/cmu-15-445-database-systems/chapter23/</link>
    <pubDate>Mon, 17 Jun 2024 17:09:19 &#43;0800</pubDate><author>junglece430@gmail.com (Jungle)</author><guid>https://Jungle430.github.io/posts/cmu-15-445-database-systems/chapter23/</guid>
    <description><![CDATA[<h1 id="cmu-15-445-database-systems">CMU 15-445 Database Systems</h1>
<h2 id="lecture-23-distributed-oltp-databases">Lecture #23: Distributed OLTP Databases</h2>
<ul>
<li>We have not discussed how to ensure that all nodes agree to commit a txn and then to make sure it does commit if the DBMS decides it should.
<ul>
<li>→ What happens if a node fails?</li>
<li>→ What happens if messages show up late?</li>
<li>→ What happens if the system does not wait for every node to agree to commit?</li>
</ul>
</li>
</ul>
<h3 id="atomic-commit-protocols"><strong>Atomic Commit Protocols</strong></h3>
<ul>
<li>多个节点要进行原子提交</li>
<li>解决方案
<ul>
<li>Two-Phase Commit (1970s)</li>
<li>Three-Phase Commit (1983)</li>
<li>Paxos (1989)</li>
<li>Raft (2013)</li>
<li>ZAB (2008? Zookeeper Atomic Broadcast protocol, <strong>Apache Zookeeper</strong>)</li>
<li>Viewstamped Replication (1988)</li>
</ul>
</li>
</ul>
<h4 id="two-phase-commit">Two-Phase Commit</h4>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter23-1.png" title="/img/CMU 15-445 Database Systems/chapter23-1.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter23-1.png" data-sub-html="<h2>Two-Phase Commit，Phase1: Prepare：询问其他节点准备好了没</h2>">
        
    </a><figcaption class="image-caption">Two-Phase Commit，<strong>Phase1: Prepare</strong>：询问其他节点准备好了没</figcaption>
    </figure>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter23-2.png" title="/img/CMU 15-445 Database Systems/chapter23-2.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter23-2.png" data-sub-html="<h2>Two-Phase Commit 其他节点认为可行，回复OK</h2>">
        
    </a><figcaption class="image-caption">Two-Phase Commit 其他节点认为可行，回复OK</figcaption>
    </figure>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter23-3.png" title="/img/CMU 15-445 Database Systems/chapter23-3.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter23-3.png" data-sub-html="<h2>Two-Phase Commit Phase2: Commit：向其他节点发送commit请求</h2>">
        
    </a><figcaption class="image-caption">Two-Phase Commit <strong>Phase2: Commit</strong>：向其他节点发送commit请求</figcaption>
    </figure>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter23-4.png" title="/img/CMU 15-445 Database Systems/chapter23-4.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter23-4.png" data-sub-html="<h2>Two-Phase Commit 本地提交完成后回复OK</h2>">
        
    </a><figcaption class="image-caption">Two-Phase Commit 本地提交完成后回复OK</figcaption>
    </figure>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter23-5.png" title="/img/CMU 15-445 Database Systems/chapter23-5.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter23-5.png" data-sub-html="<h2>告诉应用提交成功</h2>">
        
    </a><figcaption class="image-caption">告诉应用提交成功</figcaption>
    </figure>
<ul>
<li>
<p>如果有节点发送了ABORT的请求，协调者会回复应用事务回滚，然后向所有节点发送ABORT指令</p>
</li>
<li>
<p>2PC OPTIMIZATIONS</p>
<ul>
<li>
<p><strong>Early Prepare Voting</strong> <em>(Rare)</em></p>
<ul>
<li>→ If you send a query to a remote node that you know will be the last one to execute in this txn, then that node will also return their vote for the prepare phase with the query result.(如果知道是事务的最后一句我自己自己投票，不用等用户指令)</li>
</ul>
</li>
<li>
<p><strong>Early Ack After Prepare</strong> <em>(Common)</em></p>
<ul>
<li>→ If all nodes vote to commit a txn, the coordinator can send the client an acknowledgement that their txn was successful before the commit phase finishes.(提交之前先后告诉应用本次txn成功了，也有一定数据安全的风险)</li>
</ul>
</li>
</ul>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter23-6.png" title="/img/CMU 15-445 Database Systems/chapter23-6.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter23-6.png" data-sub-html="<h2>Early Ack After Prepare</h2>">
        
    </a><figcaption class="image-caption">Early Ack After Prepare</figcaption>
    </figure>
<h4 id="paxos">PAXOS</h4>
<ul>
<li>
<p>Consensus protocol where a coordinator proposes an outcome (e.g., commit or abort) and then the participants vote on whether that outcome should succeed（协调员提出来一个请求，大家投票决定）</p>
</li>
<li>
<p>Does not block if a majority of participants are available and has provably minimal message delays in the best case.（可用情况下少数服从多数）</p>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter23-7.png" title="/img/CMU 15-445 Database Systems/chapter23-7.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter23-7.png" data-sub-html="<h2>事务冲突时要进行舍弃</h2>">
        
    </a><figcaption class="image-caption">事务冲突时要进行舍弃</figcaption>
    </figure>
<hr>
<ul>
<li>
<p><strong>Two</strong> <strong>Phase Commit</strong>: Blocks if coordinator fails after the prepare message is sent, until coordinator recovers.</p>
</li>
<li>
<p><strong>Paxos</strong>: Nonblocking if a majority participants are alive, provided there is a sufficiently long period without further failures.</p>
</li>
<li>
<p><strong>Raft:</strong> Similar to Paxos but with fewer node types. Only nodes with most up-to-date log can become leaders.</p>
</li>
<li>
<p><strong>Multi-Paxos</strong>: If the system elects a single leader that oversees proposing changes for some period, then it can skip the propose phase. The system periodically renews who the leader is using another Paxos round. When there is a failure, the DBMS can fall back to full Paxos.</p>
</li>
</ul>
<h3 id="replication"><strong>Replication</strong></h3>
<ul>
<li>
<p>副本，冗余存储保证稳定性</p>
</li>
<li>
<p>Design Decisions:</p>
<ul>
<li>→ Replica Configuration</li>
<li>→ Propagation Scheme</li>
<li>→ Propagation Timing</li>
<li>→ Update Method</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>
<p><strong>Replica Configuration</strong></p>
</li>
<li>
<p><strong>Approach #1: Primary-Replica</strong></p>
<ul>
<li>→ All updates go to a designated primary for each object.</li>
<li>→ The primary propagates updates to its replicas by shipping logs.</li>
<li>→ Read-only txns may be allowed to access replicas.</li>
<li>→ If the primary goes down, then hold an election to select a new primary.</li>
</ul>
</li>
<li>
<p><strong>Approach #2: Multi-Primary</strong></p>
<ul>
<li>→ Txns can update data objects at any replica.</li>
<li>→ Replicas must synchronize with each other using an atomic commit protocol.</li>
</ul>
</li>
</ul>
<a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter23-8.png" title="/img/CMU 15-445 Database Systems/chapter23-8.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter23-8.png">
        
    </a>
<hr>
<ul>
<li><strong>K-Safety</strong>
<ul>
<li>确保线上至少有K个数据副本</li>
<li>低于该阈值，数据库直接下线</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>
<p><strong>Propagation Scheme</strong></p>
<ul>
<li>
<p><em>synchronous</em> scheme: 主库提交事务的时候要卡住去通知从节点，当从节点也提交成功后才告诉用户成功了</p>
</li>
<li>
<p><em>asynchronous</em> scheme: 主库提交完了就拉到，不管后续</p>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter23-9.png" title="/img/CMU 15-445 Database Systems/chapter23-9.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter23-9.png" data-sub-html="<h2>synchronous, asynchronous</h2>">
        
    </a><figcaption class="image-caption"><em>synchronous</em>, <em>asynchronous</em></figcaption>
    </figure>
</li>
<li>
<p>折中解决方案：半同步：等日志传送到备库，不用等备库执行完（MySQL）</p>
</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li><strong>Propagation Timing</strong>
<ul>
<li><strong>Continuous</strong>：持续不断向备库传播，难的就是回滚的问题，要主备一起回滚</li>
<li><strong>On Commit</strong>：The DBMS only sends the log messages for a txn to the replicas once the txn is commits.（主库提交完了才给备库发日志），不用在回滚上面浪费时间</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>
<p><strong>Active vs Passive</strong></p>
<ul>
<li>
<p><strong>Active-Active</strong>：主库给备库的是SQL语句，备库还要重新执行一遍</p>
</li>
<li>
<p><strong>Active-Passive</strong>：主库给备库的物理日志，备库直接执行日志就行</p>
</li>
<li>
<p>物理日志大，SQL执行慢，现实中往往是混合传播（MySQL）</p>
</li>
</ul>
</li>
</ul>
<h3 id="cap-theorem"><strong>CAP Theorem</strong></h3>
<ul>
<li>
<p>→ <strong>Consistent</strong></p>
</li>
<li>
<p>→ <strong>Always Available</strong></p>
</li>
<li>
<p>→ <strong>Network Partition Tolerant</strong>（断开网络，集群分裂还能用）</p>
</li>
<li>
<p>上述的三点永远不可能同时实现</p>
</li>
<li>
<p>拓展：联邦数据库：通过统一API来让不同种类的数据库合成一个集群，但是业界目前没有什么产品</p>
</li>
</ul>
<a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter23-10.png" title="/img/CMU 15-445 Database Systems/chapter23-10.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter23-10.png">
        
    </a>
]]></description>
</item>
<item>
    <title>CMU 15-445 Lecture #22: Introduction to Distributed Databases</title>
    <link>https://Jungle430.github.io/posts/cmu-15-445-database-systems/chapter22/</link>
    <pubDate>Mon, 17 Jun 2024 10:20:12 &#43;0800</pubDate><author>junglece430@gmail.com (Jungle)</author><guid>https://Jungle430.github.io/posts/cmu-15-445-database-systems/chapter22/</guid>
    <description><![CDATA[<h1 id="cmu-15-445-database-systems">CMU 15-445 Database Systems</h1>
<h2 id="lecture-22-introduction-to-distributed-databases">Lecture #22: Introduction to Distributed Databases</h2>
<h3 id="introduction-distributed-dbmss">Introduction Distributed DBMSs</h3>
<ul>
<li>
<p>辨析概念：Parallel DBMSs vs Distributed DBMSs</p>
</li>
<li>
<p><strong>Parallel DBMSs:</strong></p>
<ul>
<li>Nodes are physically close to each other.</li>
<li>Nodes connected with high-speed LAN(Local Area Network).</li>
<li><strong>Communication cost is assumed to be small.</strong></li>
</ul>
</li>
<li>
<p><strong>Distributed DBMSs:</strong></p>
<ul>
<li>Nodes can be far from each other.</li>
<li>Nodes connected using public network.</li>
<li><strong>Communication cost and problems cannot be ignored</strong></li>
</ul>
</li>
<li>
<p>主要的差别是通信代价，前者可以忽略，后者无法忽略</p>
</li>
</ul>
<hr>
<ul>
<li>Single node -&gt; Distributed DBMSs</li>
<li>Questions to consider
<ul>
<li><strong>Optimization &amp; Planning</strong></li>
<li><strong>Concurrency Control</strong></li>
<li><strong>Logging &amp; Recovery</strong></li>
</ul>
</li>
</ul>
<h3 id="system-architectures">System Architectures</h3>
<ul>
<li>
<p>A distributed DBMS&rsquo;s system architecture specifies <strong>what shared resources are directly accessible to CPUs.</strong></p>
</li>
<li>
<p>This affects how CPUs coordinate with each other and where they retrieve/store objects in the database.</p>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-1.png" title="/img/CMU 15-445 Database Systems/chapter22-1.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-1.png" data-sub-html="<h2>Every database node are on the same machine(Extreme Situations), like parallel DBMSs, ignore it(</h2>">
        
    </a><figcaption class="image-caption">Every database node are on the same machine(Extreme Situations), like parallel DBMSs, ignore it(</figcaption>
    </figure>
<ul>
<li>注意上面图片不是被许多XXX共享就证明其他的机器就那一个组件，为了跑起来基本的OS, CPU, memory和disk都要有，不过是那些部分参与到这个分布式的系统中</li>
</ul>
<hr>
<ul>
<li>
<p><strong>shared memory</strong></p>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-2.png" title="/img/CMU 15-445 Database Systems/chapter22-2.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-2.png" data-sub-html="<h2>A large memory and a large disk, both of them are shared by many cpus by network</h2>">
        
    </a><figcaption class="image-caption">A large memory and a large disk, both of them are shared by many cpus by network</figcaption>
    </figure>
<ul>
<li>
<p>Nodes access <strong>a common memory address space</strong> via a fast <strong>interconnect</strong>.</p>
</li>
<li>
<p>Can still use local memory / disk for intermediate results</p>
</li>
</ul>
</li>
<li>
<p>This looks a lot like shared everything. <strong>Nobody does this.</strong>(我认为原因是CPU要通过网络来访问内存，内存最大的优势”高速“直接没了)</p>
</li>
<li>
<p>在单体架构上面有使用，多路服务器（多个CPU，每个CPU多核来提高并发能力，中间是通过高速总线相连的）</p>
</li>
</ul>
<hr>
<ul>
<li>
<p><strong>shared disk</strong></p>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-3.png" title="/img/CMU 15-445 Database Systems/chapter22-3.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-3.png" data-sub-html="<h2>large disk, shared by many cpus and memories</h2>">
        
    </a><figcaption class="image-caption">large disk, shared by many cpus and memories</figcaption>
    </figure>
<ul>
<li>
<p>Nodes <strong>access a single logical disk</strong> via an interconnect, but <strong>each have their own private memories.</strong></p>
</li>
<li>
<p>Scale execution layer independently from the storage layer.（解耦了执行层和存储层，可以独立拓展来加强单个层的性能）</p>
</li>
<li>
<p>This architecture facilitates <strong>data lakes</strong> and <strong>serverless</strong> systems.？？？没太懂</p>
</li>
</ul>
</li>
<li>
<p>该架构在近年新的数据库产品中使用的及其广泛，原因就是近些年云技术的兴起，大多数公司都趋向于购买云数据库，而在云厂商的机房中很容易就能做到这种架构（云计算在设计的时候就把计算和存储分开了，所以机房往往是计算服务器和磁盘集群式分开的，每个部分取一些就是这个架构）</p>
</li>
<li>
<p>国内该架构的代表：<a href="https://github.com/ApsaraDB/PolarDB-for-PostgreSQL" target="_blank" rel="noopener noreffer">PolarDB</a></p>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-5.png" title="/img/CMU 15-445 Database Systems/chapter22-5.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-5.png" data-sub-html="<h2>查询过程，可以看到执行层和存储层分开了，Node数量决定计算能力，存储大小决定存储能力</h2>">
        
    </a><figcaption class="image-caption">查询过程，可以看到执行层和存储层分开了，Node数量决定计算能力，存储大小决定存储能力</figcaption>
    </figure>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-6.png" title="/img/CMU 15-445 Database Systems/chapter22-6.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-6.png" data-sub-html="<h2>这个架构面临的一个最大的问题就是缓存同步的问题，Node1进行了数据的更新，如果马上不刷盘（因为耗时太长），那么就需要将更新数据的信息同步到其他节点的缓存，其实无论解决那种方案，都要面临这类问题</h2>">
        
    </a><figcaption class="image-caption">这个架构面临的一个最大的问题就是缓存同步的问题，Node1进行了数据的更新，如果马上不刷盘（因为耗时太长），那么就需要将更新数据的信息同步到其他节点的缓存，其实无论解决那种方案，都要面临这类问题</figcaption>
    </figure>
</li>
</ul>
<hr>
<ul>
<li>
<p><strong>shared nothing</strong></p>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-4.png" title="/img/CMU 15-445 Database Systems/chapter22-4.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-4.png" data-sub-html="<h2>Most common situations</h2>">
        
    </a><figcaption class="image-caption"><strong>Most</strong> common situations</figcaption>
    </figure>
</li>
<li>
<p>Each DBMS node has its own CPU, memory, and local disk.</p>
</li>
<li>
<p>Nodes only communicate with each other via network</p>
<ul>
<li>
<p>Better performance &amp; efficiency.</p>
</li>
<li>
<p><strong>Harder to scale capacity.</strong></p>
</li>
<li>
<p><strong>Harder to ensure consistency.</strong></p>
</li>
<li>
<p>单层扩容（加一台机器所有能力都上去了，其他性能提示的效果因为短板效应被浪费了）和保证一致性都做的不好（数据不在同一块盘上面）</p>
</li>
<li>
<p>好处：和上面<strong>shared disk</strong>相比把盘肢解了并放在本地，提升了部分性能</p>
</li>
</ul>
</li>
<li>
<p>这类架构也在现在的分布式数据库产品中大量使用，代表产品是Redis</p>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-7.png" title="/img/CMU 15-445 Database Systems/chapter22-7.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-7.png" data-sub-html="<h2>涉及数据分区的问题，扩容也带来了数据重新分区的问题</h2>">
        
    </a><figcaption class="image-caption">涉及数据分区的问题，扩容也带来了数据重新分区的问题</figcaption>
    </figure>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-8.png" title="/img/CMU 15-445 Database Systems/chapter22-8.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-8.png" data-sub-html="<h2>不在本节点需要呼叫其他节点</h2>">
        
    </a><figcaption class="image-caption">不在本节点需要呼叫其他节点</figcaption>
    </figure>
<h3 id="design-issues"><strong>Design Issues</strong></h3>
<p><strong>Homogeneous Nodes</strong> vs. <strong>Heterogeneous Nodes:</strong></p>
<hr>
<ul>
<li>
<p><strong>Homogeneous Nodes</strong></p>
<ul>
<li>
<p>Every node in the cluster can perform the same set of tasks (albeit on potentially different partitions of data).</p>
</li>
<li>
<p>Makes provisioning and failover &ldquo;easier&rdquo;.</p>
</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li><strong>Heterogenous Nodes</strong>
<ul>
<li>Nodes are assigned specific tasks.</li>
<li>Can allow a single physical node to host multiple &ldquo;virtual&rdquo; node types for dedicated tasks.</li>
</ul>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-9.png" title="/img/CMU 15-445 Database Systems/chapter22-9.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-9.png" data-sub-html="<h2>Heterogenous Nodes on mongodb</h2>">
        
    </a><figcaption class="image-caption"><strong>Heterogenous Nodes</strong> on mongodb</figcaption>
    </figure>
<hr>
<ul>
<li>
<p><strong>DATA TRANSPARENCY</strong></p>
<ul>
<li>
<p>Applications <strong>should not be required to know where data is physically located in a distributed DBMS</strong></p>
</li>
<li>
<p>Any query that run on a single-node DBMS should produce <strong>the same result</strong> on a distributed DBMS.</p>
</li>
</ul>
</li>
<li>
<p>! In practice, developers need to be aware of the communication costs of queries to avoid excessively &ldquo;expensive&rdquo; data movement.</p>
</li>
</ul>
<hr>
<ul>
<li>
<p><strong>DATABASE PARTITIONING</strong></p>
<ul>
<li>
<p>Split database across multiple resources:</p>
<ul>
<li>
<p>Disks, nodes, processors.</p>
</li>
<li>
<p>Often called &ldquo;sharding&rdquo; in NoSQL systems.</p>
</li>
</ul>
</li>
</ul>
</li>
<li>
<p>The DBMS executes query fragments on each partition and then combines the results to produce a single answer.</p>
</li>
<li>
<p>The DBMS can partition a database <strong>physically</strong>(shared nothing) or <strong>logically</strong> (shared disk).</p>
</li>
</ul>
<hr>
<ul>
<li>
<p><strong>NAÏVE TABLE PARTITIONING</strong></p>
<ul>
<li>
<p>Assign an entire table to a single node.</p>
</li>
<li>
<p>Assumes that each node has enough storage space for an entire table.</p>
</li>
<li>
<p>Ideal if queries never join data across tables stored on different nodes and access patterns are uniform.</p>
</li>
<li>
<p>主要弱点是JOIN</p>
</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>
<p><strong>HORIZONTAL PARTITIONING</strong></p>
<ul>
<li>Split a table&rsquo;s tuples into disjoint subsets based on some partitioning key and scheme.</li>
<li>Choose column(s) that divides the database equally in terms of size, load, or usage.</li>
</ul>
</li>
<li>
<p>Partitioning Schemes:</p>
<p>→ Hashing</p>
<p>→ Ranges</p>
<p>→ Predicates</p>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-10.png" title="/img/CMU 15-445 Database Systems/chapter22-10.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-10.png" data-sub-html="<h2>Hash分区，但是如果WHERE的属性不是Hash列就要所有节点都查一遍，这种查询就很不好，查询尽量要带上Hash那列的限制</h2>">
        
    </a><figcaption class="image-caption">Hash分区，但是如果WHERE的属性不是Hash列就要所有节点都查一遍，这种查询就很不好，查询尽量要带上Hash那列的限制</figcaption>
    </figure>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-11.png" title="/img/CMU 15-445 Database Systems/chapter22-11.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-11.png" data-sub-html="<h2>扩容往往面临着新的Hash计算和分区</h2>">
        
    </a><figcaption class="image-caption">扩容往往面临着新的Hash计算和分区</figcaption>
    </figure>
<hr>
<ul>
<li>
<p><strong>CONSISTENT HASHING</strong></p>
</li>
<li>
<p>分布式系统常见的问题</p>
</li>
<li>
<p>八股：<a href="https://xiaolincoding.com/os/8_network_system/hash.html#%E5%A6%82%E4%BD%95%E5%88%86%E9%85%8D%E8%AF%B7%E6%B1%82" target="_blank" rel="noopener noreffer">什么是一致性哈希?</a></p>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-12.png" title="/img/CMU 15-445 Database Systems/chapter22-12.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-12.png" data-sub-html="<h2>P4分割了P3的一部分数据，只需要P3把这部分数据传给P4就可以了，避免了之前大规模数据迁移的情况</h2>">
        
    </a><figcaption class="image-caption">P4分割了P3的一部分数据，只需要P3把这部分数据传给P4就可以了，避免了之前大规模数据迁移的情况</figcaption>
    </figure>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-13.png" title="/img/CMU 15-445 Database Systems/chapter22-13.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-13.png" data-sub-html="<h2>P2和P6为P1的一部分数据存储副本</h2>">
        
    </a><figcaption class="image-caption">P2和P6为P1的一部分数据存储副本</figcaption>
    </figure>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-14.png" title="/img/CMU 15-445 Database Systems/chapter22-14.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-14.png" data-sub-html="<h2>存储的过程也变得冗余了（多存几份）</h2>">
        
    </a><figcaption class="image-caption">存储的过程也变得冗余了（多存几份）</figcaption>
    </figure>
<ul>
<li>物理分区和逻辑分区</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-15.png" title="/img/CMU 15-445 Database Systems/chapter22-15.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-15.png" data-sub-html="<h2>shared memory 架构下的分布式数据库不做物理分区，他的分区就是逻辑上把不同数据的查询分配给了不同的节点，物理分区常见于shared nothing架构</h2>">
        
    </a><figcaption class="image-caption">shared memory 架构下的分布式数据库不做物理分区，他的分区就是逻辑上把不同数据的查询分配给了不同的节点，物理分区常见于shared nothing架构</figcaption>
    </figure>
<h3 id="distributed-concurrency-control"><strong>Distributed Concurrency Control</strong></h3>
<ul>
<li>
<p>If our DBMS supports multi-operation and distributed txns, we need a way to coordinate their execution in the system.</p>
</li>
<li>
<p>Two different approaches:</p>
<ul>
<li>
<p>→ <strong>Centralized</strong>: Global &ldquo;traffic cop&rdquo;(“交警”).</p>
</li>
<li>
<p>→ <strong>Decentralized</strong>: Nodes organize themselves.</p>
</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li>
<p><strong>TP MONITORS</strong></p>
</li>
<li>
<p>A <strong>TP Monitor</strong> is an example of a centralized coordinator for distributed DBMSs. Originally developed in the 1970-80s to provide txns between terminals and mainframe databases.</p>
<ul>
<li>
<p>→ Examples: ATMs, Airline Reservations.</p>
</li>
<li>
<p>Standardized protocol from 1990s: X/Open XA</p>
</li>
</ul>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-16.png" title="/img/CMU 15-445 Database Systems/chapter22-16.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-16.png" data-sub-html="<h2>系统里面有一个节点专门管理每个节点的锁和事务的提交，数据库执行事务时需要申请</h2>">
        
    </a><figcaption class="image-caption">系统里面有一个节点专门管理每个节点的锁和事务的提交，数据库执行事务时需要申请</figcaption>
    </figure>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-17.png" title="/img/CMU 15-445 Database Systems/chapter22-17.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-17.png" data-sub-html="<h2>改进：数据路由和事务管理器合二为一</h2>">
        
    </a><figcaption class="image-caption">改进：数据路由和事务管理器合二为一</figcaption>
    </figure>
<ul>
<li>现在用的不多，单点很容易造成性能瓶颈</li>
</ul>
<hr>
<ul>
<li><strong>DECENTRALIZED COORDINATOR</strong></li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-18.png" title="/img/CMU 15-445 Database Systems/chapter22-18.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-18.png" data-sub-html="<h2>在节点中选出来一个Leader(老版本是master&#43;slave，后面因为政治原因不让用了，新版的数据库文档都没有这个词了)，选出来的Leader就担任了上面TP Monitor的事务职责</h2>">
        
    </a><figcaption class="image-caption">在节点中选出来一个Leader(老版本是master+slave，后面因为政治原因不让用了，新版的数据库文档都没有这个词了)，选出来的Leader就担任了上面TP Monitor的事务职责</figcaption>
    </figure>
<hr>
<ul>
<li>
<p><strong>DISTRIBUTED CONCURRENCY CONTROL</strong></p>
<ul>
<li>
<p>Many of the same protocols from single-node DBMSs can be adapted.</p>
</li>
<li>
<p>This is harder because of:</p>
<ul>
<li>→ Replication.</li>
<li>→ Network Communication Overhead.</li>
<li>→ Node Failures (Permanent + Ephemeral).</li>
<li>→ Clock Skew.(时钟不同步)</li>
</ul>
</li>
</ul>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter22-19.png" title="/img/CMU 15-445 Database Systems/chapter22-19.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter22-19.png" data-sub-html="<h2>分布式数据库的2PL很容易发生死锁，出现了死锁不容易解决，而且用网络去同步锁的开销也很大</h2>">
        
    </a><figcaption class="image-caption">分布式数据库的2PL很容易发生死锁，出现了死锁不容易解决，而且用网络去同步锁的开销也很大</figcaption>
    </figure>
]]></description>
</item>
<item>
    <title>CMU 15-445 Lecture #21: Database Crash Recovery</title>
    <link>https://Jungle430.github.io/posts/cmu-15-445-database-systems/chapter21/</link>
    <pubDate>Mon, 22 Apr 2024 11:11:57 &#43;0800</pubDate><author>junglece430@gmail.com (Jungle)</author><guid>https://Jungle430.github.io/posts/cmu-15-445-database-systems/chapter21/</guid>
    <description><![CDATA[<h1 id="cmu-15-445-database-systems">CMU 15-445 Database Systems</h1>
<h2 id="lecture-21-database-crash-recovery">Lecture #21: Database Crash Recovery</h2>
<h3 id="crash-recovery">Crash Recovery</h3>
<ul>
<li>
<p>The DBMS relies on its recovery algorithms to <strong>ensure database consistency(C), transaction atomicity(A), and durability(D)</strong> despite failures.</p>
</li>
<li>
<p>Each recovery algorithm is comprised of two parts:</p>
<ul>
<li>Actions <strong>during normal</strong> transaction processing to ensure that the DBMS can recover from a failure</li>
<li>Actions <strong>after a failure</strong> to recover the database to a state that ensures the atomicity, consistency, and durability of transactions.</li>
</ul>
</li>
<li>
<p>Check Point的问题</p>
<ul>
<li>性能问题：刷盘的时候整个DBMS都停住了</li>
<li>扫描的时候Check Point前后都要看，也很浪费效率</li>
<li>没有特别合适的刷盘频率，高了频繁小卡，低了定时大卡</li>
</ul>
</li>
<li>
<p><a href="https://en.wikipedia.org/wiki/Algorithms_for_Recovery_and_Isolation_Exploiting_Semantics" target="_blank" rel="noopener noreffer"><strong>Algorithms for Recovery and Isolation Exploiting Semantics(ARIES)</strong></a></p>
<ul>
<li>
<p>Developed at IBM Research in early 1990s for the DB2 DBMS</p>
</li>
<li>
<p>There are three key concepts in the ARIES recovery protocol:</p>
<ul>
<li>
<p><strong>Write Ahead Logging(WAL)</strong>: Any change is recorded in log on stable storage before the database change is written to disk <strong>(STEAL + NO-FORCE).</strong> 写盘策略</p>
</li>
<li>
<p><strong>Repeating History During Redo</strong>: On restart, retrace actions and restore database to exact state before crash.</p>
</li>
<li>
<p><strong>Logging Changes During Undo</strong>: Record undo actions to log to ensure action is not repeated in the event of repeated failures.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="wal-records">WAL Records</h3>
<ul>
<li>Every log record now includes a globally unique log sequence number (LSN).日志的序列号</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter21-1.png" title="/img/CMU 15-445 Database Systems/chapter21-1.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter21-1.png" data-sub-html="<h2>日志分类</h2>">
        
    </a><figcaption class="image-caption">日志分类</figcaption>
    </figure>
<ul>
<li>
<p>每个数据页会有一个<strong>pageLSN</strong>，记录这一页最新的修改</p>
</li>
<li>
<p>每个系统会有一个<strong>flushedLSN</strong>，前面的进了磁盘，后面的都在内存没有刷盘</p>
</li>
<li>
<p>脏页写回到磁盘的必要条件 $pageLST\le flushedLSN$，这个脏页之前所作的修改必须先要刷到磁盘里面去，它才能刷回到盘里面去</p>
</li>
<li>
<a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter21-2.png" title="/img/CMU 15-445 Database Systems/chapter21-2.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter21-2.png">
        
    </a>
</li>
<li>
<p>每次刷盘的时候要更新<strong>flushedLSN</strong></p>
</li>
</ul>
<h3 id="normal-execution">Normal Execution</h3>
<ul>
<li>
<p>情景：每个事务都会读和写数据，结果有commit和rollback</p>
</li>
<li>
<p>假设</p>
<ul>
<li>所有的log都在一页里面</li>
<li>写磁盘是原子操作</li>
<li>使用严格2PL</li>
<li>窃取式+非强制</li>
</ul>
</li>
<li>
<p>COMMIT</p>
<ul>
<li>log上面加一条COMMIT</li>
<li>COMMIT之前有关这个事务的所有日志都要刷盘，刷盘是连续写+同步</li>
<li>后面刷脏页的时候会追加一句TXN-END</li>
<li>刷完盘之后的数据在内存里面就可以干掉了</li>
<li><figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter21-3.png" title="/img/CMU 15-445 Database Systems/chapter21-3.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter21-3.png" data-sub-html="<h2>COMMIT证明提交成功，TXN-END代表脏页被刷回去了</h2>">
        
    </a><figcaption class="image-caption">COMMIT证明提交成功，TXN-END代表脏页被刷回去了</figcaption>
    </figure></li>
</ul>
</li>
<li>
<p>ROLLBACK</p>
<ul>
<li>
<p>加上prevLSN字段：记录这个事务的上一条日志的地点（类比双链表中的prev指针）</p>
</li>
<li>
<a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter21-4.png" title="/img/CMU 15-445 Database Systems/chapter21-4.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter21-4.png">
        
    </a>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter21-5.png" title="/img/CMU 15-445 Database Systems/chapter21-5.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter21-5.png" data-sub-html="<h2>回滚就是记录相反的日志</h2>">
        
    </a><figcaption class="image-caption">回滚就是记录相反的日志</figcaption>
    </figure>
</li>
<li>
<p>具体操作：</p>
<ul>
<li>
<p>加上ABORT</p>
</li>
<li>
<p>撤销修改，同时追加对应的回滚日志</p>
</li>
<li>
<p>清理做完了加上TXN-END的标志</p>
</li>
<li>
<p>注意：清理的过程是不可能回滚的</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="checkpointing">Checkpointing</h3>
<ul>
<li>
<p>检查点的问题</p>
<ul>
<li>要停止处理新事务，同时所有正在运行的事务都要做完才能刷盘，这个对效率的影响很大</li>
<li>改进：让所有进行中的事务暂停/给所有需要刷盘的数据加锁，而不是等他们做完</li>
</ul>
</li>
<li>
<p><strong>Active Transaction Table (ATT)</strong></p>
<ul>
<li>Checkpointing的时候还在活动的事务的表</li>
<li>One entry per currently active txn.
<ul>
<li>→ txnId: Unique txn identifier.</li>
<li>→ status: The current “mode” of the txn.</li>
<li>→ lastLSN: Most recent LSN created by txn</li>
<li>Remove entry after the TXN-END record.(TXN-END才算不活动)</li>
</ul>
</li>
<li>Txn Status Codes:
<ul>
<li>R → Running</li>
<li>C → Committing</li>
<li>U → Candidate for Undo</li>
</ul>
</li>
</ul>
</li>
<li>
<p><strong>Dirty Page Table (DPT)</strong></p>
<ul>
<li>Checkpointing的时候的脏页</li>
<li>One entry per dirty page in the buffer pool:
<ul>
<li>→ recLSN: The LSN of the log record that first caused the page to be dirty.</li>
</ul>
</li>
</ul>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter21-6.png" title="/img/CMU 15-445 Database Systems/chapter21-6.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter21-6.png" data-sub-html="<h2>记录的时候标注更多信息</h2>">
        
    </a><figcaption class="image-caption">记录的时候标注更多信息</figcaption>
    </figure>
</li>
</ul>
<hr>
<ul>
<li><strong>Fuzzy Checkpoints</strong>
<ul>
<li>Checkpointing的时候其他事务也继续运行</li>
<li>把checkpoint从一个时间点变成一个时间段(POINT -&gt; BEGIN+END)</li>
<li><figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter21-7.png" title="/img/CMU 15-445 Database Systems/chapter21-7.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter21-7.png" data-sub-html="<h2>BEGIN&#43;END</h2>">
        
    </a><figcaption class="image-caption">BEGIN+END</figcaption>
    </figure></li>
</ul>
</li>
</ul>
<h3 id="aries-recovery">ARIES Recovery</h3>
<ol>
<li><strong>Analysis</strong>: Read the WAL to identify dirty pages in the buffer pool and active transactions at the time of the crash. At the end of the analysis phase the ATT tells the DBMS which transactions were active at the time of the crash. The DPT tells the DBMS which dirty pages might not have made it to disk.</li>
<li><strong>Redo</strong>: Repeat all actions starting from an appropriate point in the log (even txns that will abort).</li>
<li><strong>Undo</strong>: Reverse the actions of transactions that did not commit before the crash.</li>
</ol>
<ul>
<li><figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter21-8.png" title="/img/CMU 15-445 Database Systems/chapter21-8.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter21-8.png" data-sub-html="<h2>恢复的过程</h2>">
        
    </a><figcaption class="image-caption">恢复的过程</figcaption>
    </figure></li>
</ul>
]]></description>
</item>
<item>
    <title>CMU 15-445 Lecture #20: Database Logging</title>
    <link>https://Jungle430.github.io/posts/cmu-15-445-database-systems/chapter20/</link>
    <pubDate>Sun, 21 Apr 2024 15:08:57 &#43;0800</pubDate><author>junglece430@gmail.com (Jungle)</author><guid>https://Jungle430.github.io/posts/cmu-15-445-database-systems/chapter20/</guid>
    <description><![CDATA[<h1 id="cmu-15-445-database-systems">CMU 15-445 Database Systems</h1>
<h2 id="lecture-20-database-logging">Lecture #20: Database Logging</h2>
<h3 id="crash-recovery">Crash Recovery</h3>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter20-1.png" title="/img/CMU 15-445 Database Systems/chapter20-1.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter20-1.png" data-sub-html="<h2>情景：数据库运行到一半没电了</h2>">
        
    </a><figcaption class="image-caption">情景：数据库运行到一半没电了</figcaption>
    </figure>
<ul>
<li>Recovery algorithms are techniques to ensure <strong>database consistency(C), transaction atomicity(A), and durability(D)</strong> <strong>despite failures(example no power)</strong></li>
<li>The key primitives that used in recovery algorithms are UNDO and REDO. Not all algorithms use both primitives.
<ul>
<li><strong>UNDO</strong>: The process of removing the effects of an incomplete or aborted transaction.</li>
<li><strong>REDO</strong>: The process of re-applying the effects of a committed transaction for durability.</li>
</ul>
</li>
</ul>
<h3 id="failure-classification">FAILURE CLASSIFICATION</h3>
<ul>
<li>
<p><strong>Type #1 – Transaction Failures</strong></p>
<ul>
<li>Logical Errors:→ Transaction cannot complete due to some internal error condition (e.g., integrity constraint violation).</li>
<li>Internal State Errors:→ DBMS must terminate an active transaction due to an error condition (e.g., deadlock).</li>
</ul>
</li>
<li>
<p><strong>Type #2 – System Failures</strong></p>
<ul>
<li>
<p>Software Failure:→ Problem with the OS or DBMS implementation (e.g., uncaught divide-by-zero exception).</p>
</li>
<li>
<p>Hardware Failure:</p>
<ul>
<li>→ The computer hosting the DBMS crashes (e.g., power plug gets pulled).</li>
<li>→ Fail-stop Assumption: Non-volatile storage contents are assumed to not be corrupted by system crash.</li>
</ul>
</li>
</ul>
</li>
<li>
<p><strong>Type #3 – Storage Media Failures</strong></p>
<ul>
<li>Non-Repairable Hardware Failure:
<ul>
<li>→ A head crash or similar disk failure destroys all or part of non-volatile storage.</li>
<li>→ Destruction is assumed to be detectable (e.g., disk controller use checksums to detect failures).</li>
<li>The recovery protocol can’t recover from this! Database must be restored from an archived version.</li>
</ul>
</li>
</ul>
</li>
<li>
<p>考虑：磁盘比内存慢的多，所以DBMS的模式是load到内存池后修改，最后刷盘</p>
<ul>
<li><strong>保证的点：只要commit成功，数据永远不会丢（除了硬盘爆炸），如果事务中间失败了，那么这个事务应该就和没发生一样</strong></li>
</ul>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter20-2.png" title="/img/CMU 15-445 Database Systems/chapter20-2.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter20-2.png" data-sub-html="<h2>方案选择：是否commit后要立即刷盘，刷盘的时候同一页其他未commit的事务修改的数据怎么处理(考虑回滚问题)</h2>">
        
    </a><figcaption class="image-caption">方案选择：是否commit后要立即刷盘，刷盘的时候同一页其他未commit的事务修改的数据怎么处理(考虑回滚问题)</figcaption>
    </figure>
<ul>
<li>
<p><strong>STEAL POLICY</strong></p>
<ul>
<li>STEAL: Is allowed.(别人没提交的数据我也刷)</li>
<li>NO-STEAL: Is not allowed.(别人没提交我就不能刷到磁盘)</li>
</ul>
</li>
<li>
<p><strong>FORCE POLICY</strong></p>
<ul>
<li>FORCE: Is required.(commit后立即刷)</li>
<li>NO-FORCE: Is not required.(不强制要求)</li>
</ul>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter20-3.png" title="/img/CMU 15-445 Database Systems/chapter20-3.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter20-3.png" data-sub-html="<h2>NO-STEAL FORCE</h2>">
        
    </a><figcaption class="image-caption">NO-STEAL FORCE</figcaption>
    </figure>
<ul>
<li>NO-STEAL FORCE
<ul>
<li>优点：好实现，不需要undo和redo的操作</li>
<li>缺点：效率低，刷盘频率太高，没有undo和redo那所有的东西都要load到内存池，也很伤害效率，能够修改数据的量收到缓存池大小的限制（缓存池就用来做的数据备份，没有写进磁盘的数据需要全部暂存在缓存池）</li>
</ul>
</li>
</ul>
<h3 id="shadow-paging">Shadow Paging</h3>
<ul>
<li>
<p>具体实现：<strong>SHADOW PAGING</strong></p>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter20-4.png" title="/img/CMU 15-445 Database Systems/chapter20-4.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter20-4.png" data-sub-html="<h2>把需要的数据Copy一份再改，改的时候也刷盘，commit之后改指针指向，最后清除原有页</h2>">
        
    </a><figcaption class="image-caption">把需要的数据Copy一份再改，改的时候也刷盘，commit之后改指针指向，最后清除原有页</figcaption>
    </figure>
<ul>
<li>Undo: 把本地复制出来的页全部干掉</li>
<li>Redo: 不需要，commit必须刷盘</li>
</ul>
</li>
<li>
<p>实际应用：SQLITE (PRE-2010)</p>
<ul>
<li><figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter20-5.png" title="/img/CMU 15-445 Database Systems/chapter20-5.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter20-5.png" data-sub-html="<h2>在硬盘上面留原始版本(undo),commit的时候刷盘</h2>">
        
    </a><figcaption class="image-caption">在硬盘上面留原始版本(undo),commit的时候刷盘</figcaption>
    </figure></li>
</ul>
</li>
<li>
<p>缺点：对磁盘有大量的随机读写，性能不好</p>
</li>
<li>
<p>思路：随机写=&gt;顺序写：WAL</p>
</li>
</ul>
<h3 id="write-ahead-loggingwal">Write-Ahead Logging（WAL）</h3>
<ul>
<li>
<p><strong>With write-ahead logging, the DBMS records all the changes made to the database in a log file (on stable storage) before the change is made to a disk page</strong></p>
</li>
<li>
<p><strong>The log contains sufficient information to perform the necessary undo and redo actions to restore the database after a crash.</strong></p>
</li>
<li>
<p><strong>The DBMS must write to disk the log file records that correspond to changes made to a database object before it can flush that object to disk.</strong></p>
</li>
<li>
<p>Buffer Pool Policy: STEAL + NO-FORCE</p>
</li>
<li>
<p>一般是&lt;BEGIN&gt;打头，&lt;COMMIT&gt;结尾，COMMIT必须是要把所有数据都刷到磁盘里面</p>
</li>
<li>
<p>日志格式</p>
<ul>
<li>
<p>Transaction Id</p>
</li>
<li>
<p>Object Id</p>
</li>
<li>
<p>Before Value (UNDO)</p>
</li>
<li>
<p>After Value (REDO)</p>
</li>
<li>
<p>Not necessary for Before Value and After Value if using append-only MVCC</p>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter20-6.png" title="/img/CMU 15-445 Database Systems/chapter20-6.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter20-6.png" data-sub-html="<h2>先刷日志再刷盘，commit代表刷日志成功</h2>">
        
    </a><figcaption class="image-caption">先刷日志再刷盘，commit代表刷日志成功</figcaption>
    </figure>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter20-7.png" title="/img/CMU 15-445 Database Systems/chapter20-7.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter20-7.png" data-sub-html="<h2>crash之后靠日志恢复</h2>">
        
    </a><figcaption class="image-caption">crash之后靠日志恢复</figcaption>
    </figure>
</li>
</ul>
</li>
<li>
<p>问题：用户commit你就要把日志刷到盘里面，但是刷盘频率高了又破坏效率</p>
<ul>
<li>优化： group commit: commit的时候卡住，凑够了几个事务再一起刷</li>
</ul>
</li>
</ul>
<h3 id="logging-schemes">Logging Schemes</h3>
<ul>
<li>
<p><strong>Physical Logging:</strong></p>
<ul>
<li>
<p>Record the byte-level changes made to a specific location in the database.</p>
</li>
<li>
<p>Example: git diff</p>
</li>
<li>
<p>缺点：会被写放大(UPDATE ALL FRO A TABLE =&gt; BIG Physical Log)</p>
</li>
</ul>
</li>
<li>
<p><strong>Logical Logging:</strong></p>
<ul>
<li>SQL</li>
<li>缺点：恢复的时候慢，还有SQL自己的缺陷(NOW()函数不能重放，LIMIT不保证次次相同，备库没有主库的索引)</li>
</ul>
</li>
<li>
<p><strong>Physiological Logging</strong></p>
<ul>
<li>基础是物理日志，混合SQL，偏移量换成槽</li>
</ul>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter20-8.png" title="/img/CMU 15-445 Database Systems/chapter20-8.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter20-8.png" data-sub-html="<h2>三种日志</h2>">
        
    </a><figcaption class="image-caption">三种日志</figcaption>
    </figure>
</li>
<li>
<p>MYSQL为什么undo和redo分开：安全，还有就是undo log可以用来做mvcc</p>
</li>
</ul>
<h3 id="checkpoints">Checkpoints</h3>
<ul>
<li>
<p>Blocking / Consistent Checkpoint Protocol:</p>
<ul>
<li>→ Pause all queries.</li>
<li>→ Flush all WAL records in memory to disk.</li>
<li>→ Flush all modified pages in the buffer pool to disk.</li>
<li>→ Write a &lt;CHECKPOINT&gt; entry to WAL and flush to disk.</li>
<li>→ Resume queries</li>
</ul>
</li>
<li>
<p>日志不清理也会爆磁盘</p>
</li>
<li>
<p>crash之后你要知道从哪恢复，类比游戏存档（坐佛/坐火）</p>
</li>
<li>
<p>缓存点停住，把日志和脏页全刷回去，然后在日志里面记上一个&lt;CHECKPOINT&gt;，表示上面的数据都刷盘了</p>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter20-9.png" title="/img/CMU 15-445 Database Systems/chapter20-9.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter20-9.png" data-sub-html="<h2>注意CHECKPOINT上面有完全提交的和半提交的, T2用redo,T3用undo</h2>">
        
    </a><figcaption class="image-caption">注意CHECKPOINT上面有完全提交的和半提交的, T2用redo,T3用undo</figcaption>
    </figure>
</li>
<li>
<p>T1在检查点之前全刷，不用管，T2检查点前有BEGIN，检查点后COMMIT，用REDO恢复，T3检查点之前有BEGIN，检查点后没有COMMIT，用UNDO恢复</p>
</li>
</ul>
<h3 id="conclusion">CONCLUSION</h3>
<ul>
<li>Write-Ahead Logging is (almost) always the best approach to handle loss of volatile storage.</li>
<li>Use incremental updates (STEAL + NO-FORCE) with checkpoints.</li>
<li>On Recovery: undo uncommitted txns + redo committed txns.</li>
</ul>
]]></description>
</item>
<item>
    <title>CMU 15-445 Lecture #19: Multi-Version Concurrency Control</title>
    <link>https://Jungle430.github.io/posts/cmu-15-445-database-systems/chapter19/</link>
    <pubDate>Sun, 21 Apr 2024 10:39:27 &#43;0800</pubDate><author>junglece430@gmail.com (Jungle)</author><guid>https://Jungle430.github.io/posts/cmu-15-445-database-systems/chapter19/</guid>
    <description><![CDATA[<h1 id="cmu-15-445-database-systems">CMU 15-445 Database Systems</h1>
<h2 id="lecture-19-multi-version-concurrency-control">Lecture #19: Multi-Version Concurrency Control</h2>
<h3 id="multi-version-concurrency-control">Multi-Version Concurrency Control</h3>
<ul>
<li>
<p>常常作为2PL和T/O的辅助手段</p>
</li>
<li>
<p>The DBMS maintains multiple physical versions of a single logical object in the database（维护多个历史版本（像git））</p>
<ul>
<li>
<p>When a txn writes to an object, the DBMS creates a new version of that object. 不改动，直接创建一个新的版本</p>
</li>
<li>
<p>When a txn reads an object, it reads the newest version that existed when the txn started.</p>
</li>
</ul>
</li>
</ul>
<blockquote>
<p>First implementations was Rdb/VMS and InterBase at DEC in early 1980s.</p>
<p>→ Both were by Jim Starkey, co-founder of NuoDB.</p>
<p>→ DEC Rdb/VMS is now “Oracle Rdb”.</p>
<p>→ InterBase was open-sourced as Firebird.</p>
</blockquote>
<ul>
<li>
<p>解决的问题</p>
<ul>
<li>Writers do not block readers.</li>
<li>Readers do not block writers.</li>
<li>我去上面读历史版本就是了</li>
</ul>
</li>
<li>
<p>Read-only txns can read a consistent snapshot without acquiring locks. 好像在读静态数据</p>
<ul>
<li>Use timestamps to determine visibility.用时间戳来确定可见性</li>
<li>MVCC naturally supports Snapshot Isolation (SI).天然支持快照隔离读</li>
</ul>
</li>
<li>
<p>Easily support time-travel queries.可以读取某一个时刻的历史版本，和IDE退到昨天的代码很像（其他方案很难做到，会把历史数据直接给写没）</p>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter19-1.png" title="/img/CMU 15-445 Database Systems/chapter19-1.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter19-1.png" data-sub-html="<h2>MVCC 写</h2>">
        
    </a><figcaption class="image-caption">MVCC 写</figcaption>
    </figure>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter19-2.png" title="/img/CMU 15-445 Database Systems/chapter19-2.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter19-2.png" data-sub-html="<h2>MVCC 读</h2>">
        
    </a><figcaption class="image-caption">MVCC 读</figcaption>
    </figure>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter19-3.png" title="/img/CMU 15-445 Database Systems/chapter19-3.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter19-3.png" data-sub-html="<h2>防止级联回滚，只读最新的commit数据</h2>">
        
    </a><figcaption class="image-caption">防止级联回滚，只读最新的commit数据</figcaption>
    </figure>
<ul>
<li>从上面的一张图可以看到T1和T2没法做到完全串行化，T2没有读到T1commit上去的数据，所以说只靠MVCC做不到完全串行化，Oracle最高隔离级别就是上面的图，快照隔离</li>
</ul>
<hr>
<ul>
<li>There are five important MVCC design considerations:
<ol>
<li>Concurrency Control Protocol</li>
<li>Version Storage</li>
<li>Garbage Collection</li>
<li>Index Management</li>
<li>Deletes</li>
</ol>
</li>
</ul>
<hr>
<ul>
<li><strong>Concurrency Control Protocol</strong>
<ul>
<li><strong>Approach #1: Timestamp Ordering</strong>: Assign txns timestamps that determine serial order.</li>
<li><strong>Approach #2: Optimistic Concurrency Control</strong>: Three-phase protocol from last class,Use private workspace for new versions.</li>
<li><strong>Approach #3: Two-Phase Locking</strong>: Txns acquire appropriate lock on physical version before they can read/write a logical tuple.</li>
</ul>
</li>
</ul>
<hr>
<h3 id="design-consideration-version-storage">Design consideration: Version Storage</h3>
<ul>
<li><strong>Version Storage</strong>
<ul>
<li>
<p>The DBMS uses the tuples’ pointer field to create a version chain per logical tuple</p>
<ul>
<li>This allows the DBMS to find the version that is visible to a particular txn at runtime.</li>
<li>Indexes always point to the “head” of the chain.</li>
</ul>
</li>
<li>
<p><strong>Approach #1: Append-Only Storage</strong>: New versions are appended to the same table space.</p>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter19-4.png" title="/img/CMU 15-445 Database Systems/chapter19-4.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter19-4.png" data-sub-html="<h2>Append-Only Storage</h2>">
        
    </a><figcaption class="image-caption">Append-Only Storage</figcaption>
    </figure>
<ul>
<li>两种插法：头插法和尾插法，头插法搜索效率高（大部分txn要最新的数据）</li>
</ul>
</li>
<li>
<p><strong>Approach #2: Time-Travel Storage</strong>: Old versions are copied to separate table space.</p>
<ul>
<li><figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter19-5.png" title="/img/CMU 15-445 Database Systems/chapter19-5.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter19-5.png" data-sub-html="<h2>Time-Travel Storage</h2>">
        
    </a><figcaption class="image-caption">Time-Travel Storage</figcaption>
    </figure></li>
</ul>
</li>
<li>
<p><strong>Approach #3: Delta Storage</strong>: The original values of the modified attributes are copied into a separate delta record space.</p>
<ul>
<li><figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter19-6.png" title="/img/CMU 15-445 Database Systems/chapter19-6.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter19-6.png" data-sub-html="<h2>Delta Storage就是Time-Travel Storage的省空间版本，只存增量</h2>">
        
    </a><figcaption class="image-caption">Delta Storage就是Time-Travel Storage的省空间版本，只存增量</figcaption>
    </figure></li>
<li>MySQL用的就是这个方案</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="design-consideration-garbage-collection">Design consideration: Garbage Collection</h3>
<ul>
<li>
<p><strong>Garbage Collection</strong></p>
<ul>
<li>
<p>历史版本不能一直存着（那样存储空间就会被严重浪费），所以需要定期回收无用的历史版本</p>
</li>
<li>
<p>怎么判断无用？</p>
<ul>
<li>现在运行的事务都看不到这个版本了(Snapshot Isolation)</li>
<li>创建这个版本的事务回滚了</li>
</ul>
</li>
<li>
<p>两个问题</p>
<ul>
<li>怎么发现过期的版本?</li>
<li>决定何时回收才能保证内存安全?</li>
</ul>
</li>
</ul>
</li>
<li>
<p><strong>Approach #1: Tuple-level</strong></p>
<ul>
<li>
<p>Find old versions by examining tuples directly.</p>
</li>
<li>
<p>Background Vacuuming vs. Cooperative Cleaning</p>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter19-8.png" title="/img/CMU 15-445 Database Systems/chapter19-8.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter19-8.png" data-sub-html="<h2>Background Vacuuming:后台清理</h2>">
        
    </a><figcaption class="image-caption">Background Vacuuming:后台清理</figcaption>
    </figure>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter19-9.png" title="/img/CMU 15-445 Database Systems/chapter19-9.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter19-9.png" data-sub-html="<h2>用位图表明那些页被更新过，只扫被更新过的页，这样可以减少GC的压力</h2>">
        
    </a><figcaption class="image-caption">用位图表明那些页被更新过，只扫被更新过的页，这样可以减少GC的压力</figcaption>
    </figure>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter19-10.png" title="/img/CMU 15-445 Database Systems/chapter19-10.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter19-10.png" data-sub-html="<h2>Cooperative Cleaning:查询的时候顺便清理</h2>">
        
    </a><figcaption class="image-caption">Cooperative Cleaning:查询的时候顺便清理</figcaption>
    </figure>
</li>
</ul>
</li>
<li>
<p><strong>Approach #2: Transaction-level</strong></p>
<ul>
<li>Txns keep track of their old versions so the DBMS does not have to scan tuples to determine visibility</li>
<li><figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter19-11.png" title="/img/CMU 15-445 Database Systems/chapter19-11.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter19-11.png" data-sub-html="<h2>事务记录自己改了什么，GC定时间戳去扫描事务的操作记录然后清理无用数据</h2>">
        
    </a><figcaption class="image-caption">事务记录自己改了什么，GC定时间戳去扫描事务的操作记录然后清理无用数据</figcaption>
    </figure></li>
</ul>
</li>
</ul>
<h3 id="design-consideration-index-management">Design consideration: Index Management</h3>
<ul>
<li>
<p>Primary key indexes point to version chain head</p>
</li>
<li>
<p>修改主键=先删除后插入</p>
</li>
<li>
<p>Secondary indexes</p>
<ul>
<li>
<p><strong>Approach #1: Logical Pointers:</strong> 记录数据的逻辑地址，比如主键的值</p>
</li>
<li>
<p><strong>Approach #2: Physical Pointers:</strong> 记录物理地址</p>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter19-12.png" title="/img/CMU 15-445 Database Systems/chapter19-12.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter19-12.png" data-sub-html="<h2>指向物理地址带来的一个严重的后果是如果版本链需要更新，那么一大批二级索引指向版本链的pointer也要更新</h2>">
        
    </a><figcaption class="image-caption">指向物理地址带来的一个严重的后果是如果版本链需要更新，那么一大批二级索引指向版本链的pointer也要更新</figcaption>
    </figure>
</li>
<li>
<p>逻辑地址就没有上面的毛病，只需要改主键索引，辅助索引就不需要变</p>
</li>
<li>
<p>还有一个折中的方案就是在物理地址索引和版本链之间加上一个表做索引到版本链的代理</p>
</li>
</ul>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter19-13.png" title="/img/CMU 15-445 Database Systems/chapter19-13.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter19-13.png" data-sub-html="<h2>删除后再插入也会出现问题</h2>">
        
    </a><figcaption class="image-caption">删除后再插入也会出现问题</figcaption>
    </figure>
</li>
<li>
<p>Delete</p>
<ul>
<li>Approach #1: Deleted Flag: Maintain a flag to indicate that the logical tuple has been deleted after the newest physical version. This can either be in the tuple header or a separate column.</li>
<li>Approach #2: Tombstone Tuple: Create an empty physical version to indicate that a logical tuple is deleted. Use a separate pool for tombstone tuples with only a special bit pattern in version chain pointer to reduce storage overhead.</li>
</ul>
</li>
<li>
<a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter19-14.png" title="/img/CMU 15-445 Database Systems/chapter19-14.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter19-14.png">
        
    </a>
</li>
</ul>
]]></description>
</item>
<item>
    <title>CMU 15-445 Lecture #18: Timestamp Ordering Concurrency Control</title>
    <link>https://Jungle430.github.io/posts/cmu-15-445-database-systems/chapter18/</link>
    <pubDate>Sat, 20 Apr 2024 20:07:38 &#43;0800</pubDate><author>junglece430@gmail.com (Jungle)</author><guid>https://Jungle430.github.io/posts/cmu-15-445-database-systems/chapter18/</guid>
    <description><![CDATA[<h1 id="cmu-15-445-database-systems">CMU 15-445 Database Systems</h1>
<h2 id="lecture-18-timestamp-ordering-concurrency-control">Lecture #18: Timestamp Ordering Concurrency Control</h2>
<h3 id="timestamp-ordering-concurrency-control">Timestamp Ordering Concurrency Control</h3>
<ul>
<li>
<p>纯用锁很影响性能，锁是一个悲观的方法</p>
</li>
<li>
<p>乐观的方法：用时间戳</p>
</li>
<li>
<p>If $TS(T_i) &lt; TS(T_j)$, then the DBMS must ensure that the execution schedule is equivalent to the serial schedule where $T_i$appears before $T_j$ .</p>
</li>
<li>
<p>Multiple implementation strategies:</p>
<ul>
<li>→ System/Wall Clock.:不可能完全准确，一般不用</li>
<li>→ Logical Counter.:单机系统一般用这个</li>
<li>→ Hybrid.:分布式系统用这个</li>
</ul>
</li>
</ul>
<h3 id="basic-timestamp-ordering-basic-to">Basic Timestamp Ordering (BASIC T/O)</h3>
<ul>
<li>
<p>Every object X is tagged with timestamp of the last txn that successfully did read/write:时间戳也分两种</p>
<ul>
<li>→ W-TS(X) – Write timestamp on X</li>
<li>→ R-TS(X) – Read timestamp on X</li>
</ul>
</li>
<li>
<p>Check timestamps for every operation:</p>
<ul>
<li>→ If txn tries to access an object <strong>“from the future”</strong>, it aborts and restarts.(不能操作“未来”的数据)</li>
</ul>
</li>
<li>
<p><strong>BASIC T/O – READS</strong></p>
<ul>
<li>Don’t read stuff from the “future.”</li>
<li>Action: Transaction Ti wants to read object X.</li>
<li>If TS(Ti) &lt; W-TS(X), this violates the timestamp order of Ti with regard to the writer of X.
<ul>
<li>→ Abort Ti and restart it with a new TS.</li>
</ul>
</li>
<li>Else:
<ul>
<li>→ Allow Ti to read X.</li>
<li>→ Update R-TS(X) to max(R-TS(X), TS(Ti))</li>
<li>→ Make a local copy of X to ensure repeatable reads for Ti.</li>
</ul>
</li>
</ul>
</li>
<li>
<p><strong>BASIC T/O – WRITES</strong></p>
<ul>
<li>Can’t write if a future transaction has read or written to the object.(不能写未来读过和写过的数据)</li>
<li>Action: Transaction Ti wants to write object X.</li>
<li>If TS(Ti) &lt; R-TS(X) or TS(Ti) &lt; W-TS(X)
<ul>
<li>→ Abort and restart Ti.</li>
</ul>
</li>
<li>Else:
<ul>
<li>→ Allow Ti to write X and update W-TS(X)</li>
<li>→ Also, make a local copy of X to ensure repeatable reads.</li>
</ul>
</li>
</ul>
</li>
<li>
<p><strong>Thomas Write Rule</strong></p>
<ul>
<li>对上述理论进行优化</li>
<li>If TS(Ti) &lt; R-TS(X) (未来有事务读了这个数据)
<ul>
<li>Abort and Restart Ti</li>
</ul>
</li>
<li>If TS(Ti) &lt; R-WS(X) (未来有事务写了这个数据，等效成我写了然后未来被覆盖掉了)
<ul>
<li>The DBMS can instead ignore the write and allow the transaction to continue instead of aborting and restarting it. This is called the Thomas Write Rule.</li>
</ul>
</li>
</ul>
</li>
<li>
<p>BASIC T/O总结</p>
<ul>
<li>优点：无锁，无死锁</li>
<li>缺点：对于长的事务可能会饥饿（一直rollback），前面的事务一旦修改数据后回滚那么后面的事务会读到错误的数据，读数据的时候需要copy一份到本地，如果读的数据过多，那么开销会很大</li>
</ul>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter18-1.png" title="/img/CMU 15-445 Database Systems/chapter18-1.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter18-1.png" data-sub-html="<h2>事务2的数据来源于事务1，事务1一旦回滚那么无法恢复事务2</h2>">
        
    </a><figcaption class="image-caption">事务2的数据来源于事务1，事务1一旦回滚那么无法恢复事务2</figcaption>
    </figure>
<h3 id="optimistic-concurrency-control-occ">Optimistic Concurrency Control (OCC)</h3>
<ul>
<li>Also based on timestamp</li>
</ul>
<hr>
<ul>
<li>
<p><u>The DBMS creates a private workspace for each txn.</u></p>
<ul>
<li>→ Any object read is copied into workspace.</li>
<li>Modifications are applied to workspace.(If data is wried, only applied to private workspace, no need to be wried to DBMS)</li>
</ul>
</li>
<li>
<p>When a txn commits, the DBMS compares workspace write set to see whether it conflicts with other txns.(提交的时候DBMS看你workspace里面写的数据，和其他事务对比看看有无冲突)</p>
</li>
<li>
<p>If there are no conflicts, the write set is installed into the “global” database.(无冲突一把全部写回到数据库里面)</p>
</li>
</ul>
<hr>
<ul>
<li><strong>OCC PHASES</strong>
<ul>
<li><strong>#1 – Read Phase:</strong> Track the read/write sets of txns and store their writes in a private workspace.</li>
<li><strong>#2 – Validation Phase:</strong> When a txn commits, check whether it conflicts with other txns.</li>
<li><strong>#3 – Write Phase:</strong> If validation succeeds, apply private changes to database. Otherwise abort and restart the txn.</li>
</ul>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter18-2.png" title="/img/CMU 15-445 Database Systems/chapter18-2.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter18-2.png" data-sub-html="<h2>OCC在提交的时候才会分配时间戳</h2>">
        
    </a><figcaption class="image-caption">OCC在提交的时候才会分配时间戳</figcaption>
    </figure>
<ul>
<li>
<p><strong>OCC – READ PHASE</strong></p>
<ul>
<li>Track the read/write sets of txns and store their writes in a private workspace.</li>
<li>The DBMS copies every tuple that the txn accesses from the shared database to its workspace ensure repeatable reads.</li>
</ul>
</li>
<li>
<p><strong>OCC – VALIDATION PHASE</strong></p>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter18-3.png" title="/img/CMU 15-445 Database Systems/chapter18-3.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter18-3.png" data-sub-html="<h2>VALIDATION PHASE的决策图，不能提交的时候发现后面的事务读/写了自己写了的数据（因为按照串行的理论，应该是后面的事务要读自己提交后的数据，但是自己还没提交，后面的事务读的是自己之前的数据！）</h2>">
        
    </a><figcaption class="image-caption">VALIDATION PHASE的决策图，不能提交的时候发现后面的事务读/写了自己写了的数据（因为按照串行的理论，应该是后面的事务要读自己提交后的数据，但是自己还没提交，后面的事务读的是自己之前的数据！）</figcaption>
    </figure>
<ul>
<li><strong>Approach #1: Backward Validation</strong>：和前面的历史数据做校验</li>
<li><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter18-4.png" title="/img/CMU 15-445 Database Systems/chapter18-4.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter18-4.png">
        
    </a></li>
<li><strong>Approach #2: Forward Validation</strong>：和未来的事务做校验</li>
<li><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter18-5.png" title="/img/CMU 15-445 Database Systems/chapter18-5.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter18-5.png">
        
    </a></li>
</ul>
</li>
<li>
<p><strong>OCC – WRITE PHASE</strong></p>
<ul>
<li>Serial Commits: → Use a global latch to limit a single txn to be in the Validation/Write phases at a time.(直接锁全表写，一是为了解决并发问题，二来由于写的数据都准备好了，所以写耗费的时间很短，对并发度的影响不高)</li>
</ul>
</li>
<li>
<p>OCC works well when the # of conflicts is low:</p>
<ul>
<li>→ All txns are read-only (ideal).</li>
<li>→ Txns access disjoint subsets of data.</li>
</ul>
</li>
<li>
<p>If the database is large and the workload is not skewed, then there is a low probability of conflict, so again locking is wasteful.</p>
</li>
<li>
<p>OCC问题</p>
<ul>
<li>本地Copy带来的额外开销</li>
<li>commit的时候校验的逻辑很麻烦，消耗性能</li>
<li>写的步骤是锁表的，也可能会称为性能瓶颈</li>
<li>一旦出了问题前面干的全部回退，这也是一种浪费，2PL能够执行到一半发现死锁直接让这个事务回退，损失就比OCC要小</li>
</ul>
</li>
</ul>
<h3 id="dynamic-databases-and-the-phantom-problem">Dynamic Databases and The Phantom Problem</h3>
<ul>
<li>2PL和OCC在完全串行化上面都有BUG。。。$\rightarrow$ 幻读</li>
<li>前面讨论的问题都是read和update的问题，但是没有讨论insert和delete的问题</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter18-6.png" title="/img/CMU 15-445 Database Systems/chapter18-6.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter18-6.png" data-sub-html="<h2>幻读的情景</h2>">
        
    </a><figcaption class="image-caption">幻读的情景</figcaption>
    </figure>
<ul>
<li>2PL和OCC有这个BUG的原因：我只能控制现存的数据，但是不管数据的插入/删除</li>
</ul>
<hr>
<ul>
<li>
<p><strong>THE PHANTOM PROBLEM</strong></p>
</li>
<li>
<p><strong>Approach #1: Re-Execute Scans</strong></p>
<ul>
<li>对可能产生幻读的行为(SELECT … FROM … GROUP BY …/insert/delete)进行记录，然后在提交的时候再扫描一遍检测有无并发的问题</li>
<li>缺点：这种扫描开销过大，性能上接受不了</li>
</ul>
</li>
<li>
<p><strong>Approach #2: Predicate Locking</strong></p>
<ul>
<li>
<p>最早由System R发明</p>
</li>
<li>
<p>Shared lock on the predicate in a WHERE clause of a SELECT query.</p>
</li>
<li>
<p>Exclusive lock on the predicate in a WHERE clause of any UPDATE, INSERT, or DELETE query</p>
</li>
<li>
<p>It is rarely implemented in systems; an example of a system that uses it is HyPer (precision locking).</p>
</li>
<li>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter18-7.jpg" title="/img/CMU 15-445 Database Systems/chapter18-7.jpg" data-thumbnail="/img/CMU 15-445 Database Systems/chapter18-7.jpg" data-sub-html="<h2>谓词锁控制数据竞争</h2>">
        
    </a><figcaption class="image-caption">谓词锁控制数据竞争</figcaption>
    </figure>
</li>
</ul>
</li>
<li>
<p><strong>Approach #3: Index Locking</strong></p>
<ul>
<li>有索引给索引上锁，没索引就要加大的列锁/表锁了</li>
</ul>
</li>
<li>
<p>MySQL的解决方案：间隙锁</p>
</li>
</ul>
<h3 id="isolation-levels">Isolation Levels</h3>
<ul>
<li>
<p>数据库很难做到完全串行，而且很多业务也不需要完全串行，所以有不同的隔离级别</p>
</li>
<li>
<p><strong>Isolation Levels (Strongest to Weakest):</strong></p>
<ul>
<li>
<p><strong>SERIALIZABLE</strong>: No Phantoms, all reads repeatable, and no dirty reads.</p>
<ul>
<li>Possible implementation: Index locks + Strict 2PL.</li>
</ul>
</li>
<li>
<p><strong>REPEATABLE READS</strong>: Phantoms may happen.</p>
<ul>
<li>Possible implementation: Strict 2PL.</li>
</ul>
</li>
<li>
<p><strong>READ-COMMITTED</strong>: Phantoms and unrepeatable reads may happen.</p>
<ul>
<li>Possible implementation: Strict 2PL for exclusive locks, immediate release of the shared lock after a read.</li>
</ul>
</li>
<li>
<p><strong>READ-UNCOMMITTED</strong>: All anomalies may happen.</p>
<ul>
<li>Possible implementation: Strict 2PL for exclusive locks, no shared locks for reads.</li>
</ul>
</li>
</ul>
</li>
<li>
<a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter18-8.png" title="/img/CMU 15-445 Database Systems/chapter18-8.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter18-8.png">
        
    </a>
</li>
<li>
<a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter18-9.png" title="/img/CMU 15-445 Database Systems/chapter18-9.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter18-9.png">
        
    </a>
</li>
<li>
<p>如果显式声明一个表是READ ONLY的话，那么数据库会进行优化（不加锁），还有的数据库会自动检测，如果没有写的操作会自动优化</p>
</li>
</ul>
]]></description>
</item>
<item>
    <title>CMU 15-445 Lecture #17: Two-Phase Locking</title>
    <link>https://Jungle430.github.io/posts/cmu-15-445-database-systems/chapter17/</link>
    <pubDate>Fri, 19 Apr 2024 17:58:06 &#43;0800</pubDate><author>junglece430@gmail.com (Jungle)</author><guid>https://Jungle430.github.io/posts/cmu-15-445-database-systems/chapter17/</guid>
    <description><![CDATA[<h1 id="cmu-15-445-database-systems">CMU 15-445 Database Systems</h1>
<h2 id="lecture-17-two-phase-locking">Lecture #17: Two-Phase Locking</h2>
<h3 id="transaction-locks">Transaction Locks</h3>
<ul>
<li>
<p>在操作数据的时候通过DBMS的锁管理器给数据上一把锁，这样就可以避免并发的数据竞争问题</p>
</li>
<li>
<p>但是这个锁怎么加怎么解的方案需要设计</p>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter17-1.png" title="/img/CMU 15-445 Database Systems/chapter17-1.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter17-1.png" data-sub-html="<h2>利用锁保证数据安全</h2>">
        
    </a><figcaption class="image-caption">利用锁保证数据安全</figcaption>
    </figure>
<ul>
<li>
<p><strong>Lock Types</strong></p>
<ul>
<li><strong>S-LOCK</strong>: Shared locks for reading(Reading Lock)</li>
<li><strong>X-LOCK</strong>: Exclusive locks for writing(Writing Lock)</li>
</ul>
</li>
<li>
<p>仅仅W(R)的时候上锁，修改完了解锁是无法修复串行化带来的问题，因为这个操作在一个事务里面只是一段，没有锁这个事务</p>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter17-2.png" title="/img/CMU 15-445 Database Systems/chapter17-2.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter17-2.png" data-sub-html="<h2>lock -&gt; W(R) -&gt; unlock下的串行问题</h2>">
        
    </a><figcaption class="image-caption">lock -&gt; W(R) -&gt; unlock下的串行问题</figcaption>
    </figure>
<h3 id="two-phase-locking2pl">Two-Phase Locking(2PL)</h3>
<ul>
<li>这个就是后面的研究人员为了避免上面加锁还是没有解决并发问题提出来的一个理论，这个加锁的理论和上面最大的不同就是不用预先知道整个事务的全貌（前面的加锁方案好多都是事后诸葛亮，但是放在真实场景下你又不可能回滚去干这玩意）</li>
<li>2PL分为两个阶段
<ul>
<li><strong>Phase #1– Growing</strong>: In the growing phase, each transaction requests the locks that it needs from the DBMS’s lock manager. The lock manager grants/denies these lock requests.</li>
<li><strong>Phase #2– Shrinking</strong>: Transactions enter the shrinking phase immediately after they release their first
lock. In the shrinking phase, transactions are only allowed to release locks. They are not allowed to acquire
new ones.</li>
</ul>
</li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter17-3.png" title="/img/CMU 15-445 Database Systems/chapter17-3.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter17-3.png" data-sub-html="<h2>2PL Two Phases</h2>">
        
    </a><figcaption class="image-caption">2PL Two Phases</figcaption>
    </figure>
<ul>
<li>2PL的问题: <strong>cascading aborts</strong></li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter17-4.png" title="/img/CMU 15-445 Database Systems/chapter17-4.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter17-4.png" data-sub-html="<h2>Shrinking阶段如果Rollback，会造成其他事务读到了你上面修改过但未commit的数据</h2>">
        
    </a><figcaption class="image-caption">Shrinking阶段如果Rollback，会造成其他事务读到了你上面修改过但未commit的数据</figcaption>
    </figure>
<ul>
<li>Solution: <strong>Strong Strict 2PL (aka Rigorous 2PL)</strong></li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter17-5.png" title="/img/CMU 15-445 Database Systems/chapter17-5.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter17-5.png" data-sub-html="<h2>Strong Strict 2PL解决了cascading aborts问题</h2>">
        
    </a><figcaption class="image-caption">Strong Strict 2PL解决了cascading aborts问题</figcaption>
    </figure>
<hr>
<h3 id="deadlock-handling">Deadlock Handling</h3>
<ul>
<li>2PL的另一个问题: <strong>Dead-Locks</strong></li>
</ul>
<figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter17-6.png" title="/img/CMU 15-445 Database Systems/chapter17-6.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter17-6.png" data-sub-html="<h2>Strong Strict 2PL解决不了Dead-Lock的问题，出来环锁基本就解不开了</h2>">
        
    </a><figcaption class="image-caption">Strong Strict 2PL解决不了Dead-Lock的问题，出来环锁基本就解不开了</figcaption>
    </figure>
<ul>
<li>
<p>Two ways of dealing with deadlocks:</p>
<ul>
<li>
<p>→ Approach #1: <strong>Deadlock Detection</strong>:DBMS会维护一个waits-for graph来描述所有并发的事务谁在等谁的锁</p>
<ul>
<li>Nodes are transactions</li>
<li>Edge from $T_i$ to $T_j$ if $T_i$ is waiting for $T_j$ to release a lock.</li>
<li><figure><a class="lightgallery" href="/img/CMU%2015-445%20Database%20Systems/chapter17-7.png" title="/img/CMU 15-445 Database Systems/chapter17-7.png" data-thumbnail="/img/CMU 15-445 Database Systems/chapter17-7.png" data-sub-html="<h2>The system periodically checks for cycles in waits-for graph and then decides how to break it.</h2>">
        
    </a><figcaption class="image-caption">The system periodically checks for cycles in waits-for graph and then decides how to break it.</figcaption>
    </figure></li>
<li>When the DBMS detects a deadlock, it will <strong>select a “victim” transaction to rollback(rollback or restart) to break the cycle.</strong></li>
<li>权衡: 检测周期和死锁解开时间反相关，和开销正相关，还有就是干掉那个事务(执行时间，young还是old，执行了几条SQL，加了几个锁)</li>
<li><strong>Deadlock handling: rollback length</strong>
<ul>
<li>Approach #1: <strong>Completely</strong> → Rollback entire txn and tell the application it was aborted.</li>
<li>Approach #2: <strong>Partial (Savepoints)</strong> → DBMS rolls back a portion of a txn (to break deadlock) and then attempts to re-execute the undone queries.</li>
</ul>
</li>
</ul>
</li>
<li>
<p>→ Approach #2: <strong>Deadlock Prevention</strong></p>
<ul>
<li>
<p>给每个事务加上时间戳，越靠前的事务越老，越靠后的事务越年轻</p>
</li>
<li>
<p>Older Timestamp = Higher Priority (e.g., T1 &gt; T2)</p>
</li>
<li>
<p><strong>Wait-Die (“Old Waits for Young”)</strong>:</p>
<ul>
<li>If requesting txn has higher priority than holding txn, then requesting txn waits for holding txn. (老事务碰到年轻的事务占有锁，就等到年轻的事务解锁)</li>
<li>Otherwise requesting txn aborts.(反之年轻的事务等老事务的锁，直接rollback自杀)</li>
</ul>
</li>
<li>
<p><strong>Wound-Wait (“Young Waits for Old”)</strong></p>
<ul>
<li>If requesting txn has higher priority than holding txn, then holding txn aborts and releases lock(老的事务要锁，发现整个锁被年轻的事务持有，直接rollback年轻的事务然后抢锁)</li>
<li>Otherwise requesting txn waits.(年轻的事务发现锁在老的事务哪里，那就等老的事务解锁)</li>
</ul>
</li>
<li>
<p>这个主要的思路就是解决了构成死锁条件里面“持有并等待”的条件，冲突了直接开抢</p>
</li>
<li>
<p>注意: restart的txn的时间戳用上次的时间戳，不然可能会造成饥饿</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="lock-granularities">Lock Granularities</h3>
<ul>
<li>
<p>获取锁的时候是获取属性锁，行锁，表锁，还是库锁？整个需要DBMS来负责，需要保证你加锁的数量尽可能小(10亿行锁 vs 一张表锁)，也需要考虑对并发度的影响</p>
</li>
<li>
<p><strong>Intention Lock</strong>:高层级的锁会有标记来判断下面有没有加锁的（比如表锁会记录下面的行有没有加锁的），节省了向下检索的效率</p>
<ul>
<li>意向锁也有S锁和X锁</li>
</ul>
</li>
<li>
<p>分层的锁在实际工程中相当好用</p>
</li>
<li>
<p><strong>LOCK ESCALATION</strong></p>
<ul>
<li>如果下层的锁过多了，那么DBMS就会自动升级成高层的锁（怎么和JVM的锁升级机制的思想很像？）</li>
</ul>
</li>
<li>
<p>一般加锁都是DBMS自动负责的，但是用户可以用SQL手动来加锁</p>
</li>
</ul>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-mysql" data-lang="mysql"><span class="line"><span class="cl"><span class="k">LOCK</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="o">&lt;</span><span class="k">table</span><span class="o">&gt;</span><span class="w"> </span><span class="o">&lt;</span><span class="n">mode</span><span class="o">&gt;</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">SELECT</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="o">&lt;</span><span class="k">table</span><span class="o">&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">WHERE</span><span class="w"> </span><span class="o">&lt;</span><span class="n">qualification</span><span class="o">&gt;</span><span class="w"> </span><span class="k">FOR</span><span class="w"> </span><span class="k">UPDATE</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="c1">#这样告诉了MYSQL这个不加读锁，加写锁(后面要UPDATE)
</span></span></span></code></pre></td></tr></table>
</div>
</div><h3 id="conclusion">CONCLUSION</h3>
<ul>
<li>
<p>2PL is used in almost every DBMS.</p>
</li>
<li>
<p>Automatically generates correct interleaving:</p>
<ul>
<li>Locks + protocol (2PL, SS2PL &hellip;)</li>
<li>Deadlock detection + handling</li>
<li>Deadlock prevention</li>
</ul>
</li>
</ul>
]]></description>
</item>
</channel>
</rss>
