learn.lianglianglee.com/专栏/MySQL实战45讲/00 开篇词 这一次,让我们一起来搞懂MySQL.md.html
2022-05-11 18:57:05 +08:00

941 lines
23 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>00 开篇词 这一次让我们一起来搞懂MySQL.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a class="current-tab" href="/专栏/MySQL实战45讲/00 开篇词 这一次让我们一起来搞懂MySQL.md.html">00 开篇词 这一次让我们一起来搞懂MySQL.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/01 基础架构一条SQL查询语句是如何执行的.md.html">01 基础架构一条SQL查询语句是如何执行的.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/02 日志系统一条SQL更新语句是如何执行的.md.html">02 日志系统一条SQL更新语句是如何执行的.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/03 事务隔离:为什么你改了我还看不见?.md.html">03 事务隔离:为什么你改了我还看不见?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/04 深入浅出索引(上).md.html">04 深入浅出索引(上).md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/05 深入浅出索引(下).md.html">05 深入浅出索引(下).md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/06 全局锁和表锁 :给表加个字段怎么有这么多阻碍?.md.html">06 全局锁和表锁 :给表加个字段怎么有这么多阻碍?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/07 行锁功过:怎么减少行锁对性能的影响?.md.html">07 行锁功过:怎么减少行锁对性能的影响?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/08 事务到底是隔离的还是不隔离的?.md.html">08 事务到底是隔离的还是不隔离的?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/09 普通索引和唯一索引,应该怎么选择?.md.html">09 普通索引和唯一索引,应该怎么选择?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/10 MySQL为什么有时候会选错索引.md.html">10 MySQL为什么有时候会选错索引.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/11 怎么给字符串字段加索引?.md.html">11 怎么给字符串字段加索引?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/12 为什么我的MySQL会“抖”一下.md.html">12 为什么我的MySQL会“抖”一下.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/13 为什么表数据删掉一半,表文件大小不变?.md.html">13 为什么表数据删掉一半,表文件大小不变?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/14 count()这么慢,我该怎么办?.md.html">14 count()这么慢,我该怎么办?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/15 答疑文章(一):日志和索引相关问题.md.html">15 答疑文章(一):日志和索引相关问题.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/16 “order by”是怎么工作的.md.html">16 “order by”是怎么工作的.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/17 如何正确地显示随机消息?.md.html">17 如何正确地显示随机消息?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/18 为什么这些SQL语句逻辑相同性能却差异巨大.md.html">18 为什么这些SQL语句逻辑相同性能却差异巨大.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/19 为什么我只查一行的语句,也执行这么慢?.md.html">19 为什么我只查一行的语句,也执行这么慢?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/20 幻读是什么,幻读有什么问题?.md.html">20 幻读是什么,幻读有什么问题?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/21 为什么我只改一行的语句,锁这么多?.md.html">21 为什么我只改一行的语句,锁这么多?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/22 MySQL有哪些“饮鸩止渴”提高性能的方法.md.html">22 MySQL有哪些“饮鸩止渴”提高性能的方法.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/23 MySQL是怎么保证数据不丢的.md.html">23 MySQL是怎么保证数据不丢的.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/24 MySQL是怎么保证主备一致的.md.html">24 MySQL是怎么保证主备一致的.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/25 MySQL是怎么保证高可用的.md.html">25 MySQL是怎么保证高可用的.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/26 备库为什么会延迟好几个小时?.md.html">26 备库为什么会延迟好几个小时?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/27 主库出问题了,从库怎么办?.md.html">27 主库出问题了,从库怎么办?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/28 读写分离有哪些坑?.md.html">28 读写分离有哪些坑?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/29 如何判断一个数据库是不是出问题了?.md.html">29 如何判断一个数据库是不是出问题了?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/30 答疑文章(二):用动态的观点看加锁.md.html">30 答疑文章(二):用动态的观点看加锁.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/31 误删数据后除了跑路,还能怎么办?.md.html">31 误删数据后除了跑路,还能怎么办?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/32 为什么还有kill不掉的语句.md.html">32 为什么还有kill不掉的语句.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/33 我查这么多数据,会不会把数据库内存打爆?.md.html">33 我查这么多数据,会不会把数据库内存打爆?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/34 到底可不可以使用join.md.html">34 到底可不可以使用join.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/35 join语句怎么优化.md.html">35 join语句怎么优化.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/36 为什么临时表可以重名?.md.html">36 为什么临时表可以重名?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/37 什么时候会使用内部临时表?.md.html">37 什么时候会使用内部临时表?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/38 都说InnoDB好那还要不要使用Memory引擎.md.html">38 都说InnoDB好那还要不要使用Memory引擎.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/39 自增主键为什么不是连续的?.md.html">39 自增主键为什么不是连续的?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/40 insert语句的锁为什么这么多.md.html">40 insert语句的锁为什么这么多.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/41 怎么最快地复制一张表?.md.html">41 怎么最快地复制一张表?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/42 grant之后要跟着flush privileges吗.md.html">42 grant之后要跟着flush privileges吗.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/43 要不要使用分区表?.md.html">43 要不要使用分区表?.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/44 答疑文章(三):说一说这些好问题.md.html">44 答疑文章(三):说一说这些好问题.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/45 自增id用完怎么办.md.html">45 自增id用完怎么办.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/我的MySQL心路历程.md.html">我的MySQL心路历程.md.html</a>
</li>
<li>
<a href="/专栏/MySQL实战45讲/结束语 点线网面一起构建MySQL知识网络.md.html">结束语 点线网面一起构建MySQL知识网络.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>00 开篇词 这一次让我们一起来搞懂MySQL</h1>
<p>你好,我是林晓斌,网名“丁奇”,欢迎加入我的专栏,和我一起开始 MySQL 学习之旅。我曾先后在百度和阿里任职,从事 MySQL 数据库方面的工作,一步步地从一个数据库小白成为 MySQL 内核开发人员。回想起来,从我第一次带着疑问翻 MySQL 的源码查到答案至今,已经有十个年头了。在这个过程中,走了不少弯路,但同时也收获了很多的知识和思考,希望能在这个专栏里分享给你。</p>
<p>记得刚开始接触 MySQL是我在百度贴吧做权限系统的时候。我们遇到了一个奇怪的问题一个正常 10 毫秒就能完成的 SQL 查询请求偶尔要执行 100 多毫秒才结束。当时主管问我是什么原因,我其实也搞不清楚,就上网查答案,但怎么找都找不到,又脸皮薄不想说自己不知道,只好硬着头皮翻源码。后来遇到了越来越多的问题,也是类似的情景,所以我逐步养成了通过分析源码理解原理的习惯。</p>
<p>当时,我自己的感觉是,即使我只是一个开发工程师,只是 MySQL 的用户,在了解了一个个系统模块的原理后,再来使用它,感觉是完全不一样的。当在代码里写下一行数据库命令的时候,我就能想到它在数据库端将怎么执行,它的性能是怎么样的,怎样写能让我的应用程序访问数据库的性能最高。进一步,哪些数据处理让数据库系统来做性能会更好,哪些数据处理在缓存里做性能会更好,我心里也会更清楚。在建表和建索引的时候,我也会更有意识地为将来的查询优化做综合考虑,比如确定是否使用递增主键、主键的列怎样选择,等等。</p>
<p>但随后我又有了一个新的困惑,我觉得自己了解的 MySQL 知识点是零散的,没有形成网络。于是解决完一个问题后,很容易忘记。再碰到类似的问题,我又得再翻一次代码。</p>
<p>所幸在阿里工作的时候,我参与了阿里云关系型数据库服务内核的开发,并且负责开发开源分支 AliSQL让我对 MySQL 内核和源码有了更深层次的研究和理解。在服务内部客户和公有云客户的过程中,我有机会面对和解决足够多的问题,再通过手册进行系统的学习,算是比较坎坷地将 MySQL 的知识网络补了起来。</p>
<p>所以,在回顾这个过程的时候,我的第一个感受是,如果一开始就有一些从理论到实战的系统性指导,那该多好啊,也许我可以学习得更快些。</p>
<p>在极客时间团队跟我联系策划这个专栏的时候,我还是持怀疑态度的。为什么呢?现在不比当年了,犹记得十余年前,你使用 MySQL 的过程中碰到问题的话,基本上都只能到代码里去找答案,因为那时网上的资料太少了。</p>
<p>而近十年来MySQL 在中国广泛普及,技术分享文章可以说是浩如烟海。所以,现在要系统地介绍一遍 MySQL 的话,恐怕里面提及的大多数知识点,都可以在社区文章中找到。那么我们做这个专栏的意义在哪里,而它又凭什么可以收费呢?</p>
<p>直到收到极客时间团队的答复,我才开始对这个专栏“想做和可以做”的事情感觉清晰起来。数据库是一个综合系统,其背后是发展了几十年的数据库理论。同时,数据库系统也是一个应用系统,可能一个业务开发人员用了两三年 MySQL还未必清楚那些自己一直在用的“最佳实践”为什么是最佳的。</p>
<p>于是,我希望这个专栏能够帮助这样的一些开发者:他们正在使用 MySQL知道如何写出逻辑正确的 SQL 语句来实现业务目标,却不确定这个语句是不是最优的;他们听说了一些使用数据库的最佳实践,但是更想了解为什么这么做;他们使用的数据库偶尔会出问题,亟需了解如何更快速、更准确地定位问题,甚至自己解决问题……</p>
<p>在过去的七年里,我带过十几个应届毕业生,看着他们成长,要求他们原理先行,再实践验证。几年下来,他们的成长速度都很快,其中好几个毕业没两年就成为团队的骨干力量了。我也在社招的时候面试过很多有着不错的运维实践经验和能力的候选人,但都因为对数据库原理仅有一知半解的了解,而最终遗憾地没有通过面试。</p>
<p>因此,我希望这个专栏能够激发开发者对数据库原理的探索欲,从而更好地理解工作中遇到的问题,更能知道背后的为什么。所以<strong>我会选那些平时使用数据库时高频出现的知识,如事务、索引、锁等内容构成专栏的主线</strong>。这些主线上是一个个的知识点。每个点就是一个概念、一个机制或者一个原理说明。在每个说明之后,我会和你讨论一个实践相关的问题。</p>
<p>希望能以这样的方式,让你对 MySQL 的几条主线有一个整体的认识,并且了解基本概念。在之后的实践篇中,我会引用到这些主线的知识背景,并着力说明它们是怎样指导实践的。这样,<strong>你可以从点到线,再到面,形成自己的 MySQL 知识网络。</strong></p>
<p>在这里,有一份目录,你也可以先了解下整个专栏的知识结构。</p>
<p><img src="assets/a78db0b99bbf1149c39b7960f7183c7e.jpg" alt="img" /></p>
<p>如前面说的,这几条主线上的每个知识点几乎都不是最新的,有些甚至十年前就这样,并没有改过。但我希望针对这些点的说明,可以让你在使用 MySQL 时心里更有底,知道怎么做选择,并且明白为什么。了解了原理,才能在实践中不断创新,提升个人的价值和工作输出。</p>
</div>
</div>
<div>
<div style="float: right">
<a href="/专栏/MySQL实战45讲/01 基础架构一条SQL查询语句是如何执行的.md.html">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"7099728cb80f3d60","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>