習(xí)路線:從安裝配置到執(zhí)行計(jì)劃與面試實(shí)戰(zhàn))
簡(jiǎn)介一套面向MySQL初學(xué)者的系統(tǒng)學(xué)習(xí)資料包適合正在學(xué)習(xí)SQL、準(zhǔn)備數(shù)據(jù)庫(kù)課程或希望夯實(shí)關(guān)系型數(shù)據(jù)庫(kù)基礎(chǔ)的讀者。內(nèi)容覆蓋SQL基礎(chǔ)語(yǔ)法、多表查詢、子查詢、聚合函數(shù)、視圖、存儲(chǔ)過(guò)程、觸發(fā)器、事務(wù)與索引并延伸到性能優(yōu)化與Web開(kāi)發(fā)集成可作為從入門(mén)到進(jìn)階的課程配套資源。壓縮包共41個(gè)文件包含20個(gè)PDF講義、19個(gè)SQL腳本和2個(gè)Markdown說(shuō)明文檔整體約21.88MBPDF按章節(jié)拆解知識(shí)點(diǎn)SQL腳本可直接運(yùn)行練習(xí)md文檔用于項(xiàng)目說(shuō)明。已有217人學(xué)習(xí)資料編排清晰便于邊看邊練、查漏補(bǔ)缺能夠幫初學(xué)者快速建立MySQL實(shí)戰(zhàn)能力。 作為一個(gè)經(jīng)常在論壇和社群里潛水看數(shù)據(jù)庫(kù)相關(guān)討論的人我發(fā)現(xiàn)一個(gè)很有意思的現(xiàn)象每次有人求“MySQL學(xué)習(xí)資料”真正被扔出來(lái)的鏈接反而不是官方文檔也不是系統(tǒng)課程而是一串更具體的熱搜詞——“mysql安裝教程”“mysql命令大全”“mysql面試題”“error 2002 (HY000): cant connect to local mysql server through socket”——這些詞恰好就是新手最容易卡住的地方。這份學(xué)習(xí)資料不打算重復(fù)官方手冊(cè)而是把“怎么學(xué)”這件事拆成一條能照著走的路把安裝選擇、SQL基本功、執(zhí)行計(jì)劃、報(bào)錯(cuò)排查、面試重點(diǎn)串成一條完整路徑。無(wú)論你是剛裝好MySQL還沒(méi)建過(guò)表的新手還是想系統(tǒng)補(bǔ)基礎(chǔ)、準(zhǔn)備跳槽面試的開(kāi)發(fā)都能在對(duì)應(yīng)章節(jié)找到能吃下去的東西。1. 先把版本和安裝方式定下來(lái)后面能少踩一半坑1.1 MySQL 8.0和5.7的差別不只是版本號(hào)變了現(xiàn)在這個(gè)時(shí)間點(diǎn)新項(xiàng)目我個(gè)人建議直接上8.0別再糾結(jié)5.7了。搜索“mysql 8.0 版本穩(wěn)定版安裝包下載”“mysql 8.0 安裝 配置 教程”的熱度一直很高說(shuō)明大家都在往8.0遷移但遷移之后踩的坑也不少我先把最重要的差異列出來(lái)默認(rèn)字符集8.0默認(rèn)就是utf8mb45.7默認(rèn)還是utf8mb3。這意味著8.0建表不用再為emoji、生僻字、中文排序額外折騰字符集配置。窗口函數(shù)和CTE8.0支持ROW_NUMBER()、RANK()、LAG()這類窗口函數(shù)也支持WITH ... AS這種公共表表達(dá)式。寫(xiě)排名、同比環(huán)比、分組TopN這種統(tǒng)計(jì)SQL5.7要拼變量或者用子查詢8.0一行窗口函數(shù)就結(jié)束了體驗(yàn)完全不是一個(gè)層級(jí)。認(rèn)證插件8.0的默認(rèn)認(rèn)證插件是caching_sha2_password5.7是mysql_native_password。這個(gè)變化最容易坑人——你裝好8.0拿舊版Navicat去連直接報(bào)錯(cuò)“Authentication plugin caching_sha2_password cannot be loaded”。解決辦法一個(gè)是升級(jí)客戶端一個(gè)是在建用戶時(shí)指定老插件。學(xué)習(xí)階段我的建議是直接升級(jí)客戶端別把密碼搞成老協(xié)議養(yǎng)成好習(xí)慣更重要。還有一個(gè)學(xué)習(xí)資料里的重點(diǎn)8.0對(duì)索引、優(yōu)化器、InnoDB引擎本身也做了很多改進(jìn)比如不可見(jiàn)索引、降序索引、函數(shù)索引。這些特性在面試?yán)镆矔?huì)被問(wèn)到學(xué)習(xí)時(shí)最好直接拿8.0做實(shí)驗(yàn)別在5.7上練完再換8.0很多行為對(duì)不上。1.2 Windows、macOS、Docker三條安裝路徑怎么選“mysql安裝教程”“mysql安裝配置教程”是絕對(duì)的高頻熱詞。我見(jiàn)過(guò)太多人一開(kāi)始就死在安裝上裝了一半報(bào)錯(cuò)服務(wù)起不來(lái)然后心態(tài)崩了。先說(shuō)結(jié)論學(xué)習(xí)用怎么裝都行但如果你電腦上還要跑別的環(huán)境建議優(yōu)先Docker。安裝方式適合場(chǎng)景關(guān)鍵注意點(diǎn)Windows官方安裝包新手入門(mén)想要圖形化界面安裝時(shí)選Server only別裝一堆用不上的組件macOS HomebrewmacOS用戶命令行習(xí)慣brew install mysql裝完跑mysql_secure_installationDocker容器不污染本機(jī)環(huán)境版本切換方便記得掛數(shù)據(jù)卷否則容器刪了數(shù)據(jù)全沒(méi)Windows下安裝包方式最常踩的坑是兩個(gè)。第一個(gè)是安裝到“配置MySQL Server”那一步root密碼設(shè)置完了但字符集忘了選utf8mb4后面建庫(kù)建表再改就很麻煩。第二個(gè)是本地有殘留的MySQL服務(wù)安裝時(shí)端口3306被占用或者服務(wù)名沖突建議安裝前先確認(rèn)一下“服務(wù)”里有沒(méi)有mysql殘留。macOS用戶用Homebrew最省心brew install mysql brew services start mysql mysql_secure_installation第三行那個(gè)安全初始化腳本會(huì)引導(dǎo)你設(shè)置root密碼、是否移除匿名用戶、是否禁止root遠(yuǎn)程登錄新手按提示一路走下去就行。mac上如果遇到“Cant connect to local MySQL server through socket /tmp/mysql.sock ”十有八九是服務(wù)沒(méi)起來(lái)先檢查brew services list。Docker安裝是另一種思路測(cè)試多版本、以后玩主從復(fù)制都方便docker run --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDyourpassword \ -v /my/own/datadir:/var/lib/mysql \ -d mysql:8.0-v那個(gè)參數(shù)是數(shù)據(jù)卷掛載會(huì)把容器里的數(shù)據(jù)目錄映射到宿主機(jī)這樣刪容器也不丟數(shù)據(jù)。不少人在“docker安裝mysql”之后栽在“默認(rèn)密碼”上——其實(shí)Docker鏡像創(chuàng)建容器時(shí)MYSQL_ROOT_PASSWORD環(huán)境變量指定的就是root密碼但如果你之前創(chuàng)建過(guò)同名容器密碼可能被緩存了建議用docker ps -a看看有沒(méi)有殘留容器。1.3 環(huán)境變量和服務(wù)的坑提前說(shuō)透Windows用戶裝完最氣人的一句提示是“mysql不是內(nèi)部或外部命令”。這不是MySQL沒(méi)裝上是環(huán)境變量沒(méi)配。安裝目錄下的bin文件夾路徑要加到系統(tǒng)的Path環(huán)境變量里加完之后重新開(kāi)一個(gè)CMD窗口才生效。另外“安裝mysql啟動(dòng)服務(wù)報(bào)錯(cuò)”這個(gè)熱詞背后最常見(jiàn)的原因有三類配置文件my.ini路徑不對(duì)服務(wù)啟動(dòng)時(shí)找不到報(bào)1067錯(cuò)誤。data目錄初始化失敗。Windows安裝時(shí)如果以前殘留過(guò)data目錄新版本不會(huì)幫你清。端口被占用另一個(gè)MySQL實(shí)例或者別的程序占了3306。排查的時(shí)候先看錯(cuò)誤日志日志比任何“經(jīng)驗(yàn)”都可靠。Windows下日志默認(rèn)在MySQL安裝目錄下的data文件夾打開(kāi).err結(jié)尾的文件直接搜[ERROR]基本能看到根本原因。2. SQL基本功里這四件事很容易被忽略2.1 “命令大全”不用死記先學(xué)會(huì)看幫助和元數(shù)據(jù)每次搜“mysql數(shù)據(jù)庫(kù)命令大全”出來(lái)都是一長(zhǎng)串SHOW命令列表。我說(shuō)句實(shí)在話這種東西存下來(lái)當(dāng)字典查可以拿來(lái)到處背就是浪費(fèi)時(shí)間。真正每天要用的其實(shí)就那么幾個(gè)——SHOW DATABASES、SHOW TABLES、DESC、SHOW CREATE TABLE、SHOW INDEX FROM前四個(gè)用來(lái)快速了解庫(kù)表結(jié)構(gòu)最后一個(gè)用來(lái)排查索引情況。MySQL自帶了一個(gè)很實(shí)用的幫助功能在命令行里輸入HELP SELECT; HELP SHOW;它會(huì)直接給出相關(guān)語(yǔ)法說(shuō)明。遇到不確定的語(yǔ)法先查HELP比打開(kāi)瀏覽器搜一堆廣告頁(yè)面快得多。另外建議養(yǎng)成看元數(shù)據(jù)的習(xí)慣。information_schema這個(gè)庫(kù)就是一個(gè)“數(shù)據(jù)庫(kù)的數(shù)據(jù)庫(kù)”里面存了所有表、字段、索引、鎖、事務(wù)的信息排查問(wèn)題時(shí)會(huì)頻繁用到比如第4部分要講的鎖表排查。2.2 排序和分組里的隱藏行為背下來(lái)不如親手試一遍“mysql排序”這個(gè)熱詞太籠統(tǒng)了但新手翻車的地方很具體。第一是NULL排序。默認(rèn)升序時(shí)NULL排在最前面降序時(shí)NULL排在最后面。如果你希望NULL排最后要寫(xiě)成ORDER BY col IS NULL, col而不是在ORDER BY后面加奇奇怪怪的DESC。第二是中文字段排序。默認(rèn)utf8mb4字符集下ORDER BY中文是按Unicode碼點(diǎn)排的不是按拼音排的也不是按筆畫(huà)排的。想按拼音排序可以SELECT name FROM user ORDER BY CONVERT(name USING gbk);第三是WHERE和HAVING的差別。WHERE在分組前過(guò)濾原始行HAVING在分組后過(guò)濾聚合結(jié)果。記住這個(gè)原則就不會(huì)寫(xiě)出WHERE COUNT(*) 10這種報(bào)錯(cuò)SQL了。分組統(tǒng)計(jì)還有一個(gè)高頻場(chǎng)景GROUP BY之后想拿到每組最新的記錄、每組TopN8.0窗口函數(shù)一行搞定但很多人還在寫(xiě)5.7時(shí)代的嵌套子查詢。這類題筆試面試都愛(ài)出建議把窗口函數(shù)練熟。2.3 行轉(zhuǎn)列經(jīng)典中的經(jīng)典“mysql 行轉(zhuǎn)列”在熱詞里排得很靠前原因很簡(jiǎn)單筆試面試、實(shí)際報(bào)表需求都經(jīng)常碰到。本質(zhì)是把一張“長(zhǎng)表”每行是一個(gè)維度值變成“寬表”每個(gè)維度值變成一列。假設(shè)有張訂單表每行是某個(gè)用戶某個(gè)月的消費(fèi)金額SELECT user_id, SUM(CASE WHEN month 202401 THEN amount ELSE 0 END) AS m202401, SUM(CASE WHEN month 202402 THEN amount ELSE 0 END) AS m202402, SUM(CASE WHEN month 202403 THEN amount ELSE 0 END) AS m202403 FROM pay_record GROUP BY user_id;為什么用SUM(CASE WHEN ...)而不是MAX因?yàn)樵诜纸M內(nèi)同一個(gè)用戶同一個(gè)月份如果有多條記錄SUM才是累加總額如果業(yè)務(wù)上能保證一行最多一條記錄用MAX也能得到同樣結(jié)果。面試官問(wèn)“SUM和MAX選哪個(gè)”考的就是你對(duì)數(shù)據(jù)粒度是否敏感。反過(guò)來(lái)列轉(zhuǎn)行用UNION ALL或者M(jìn)ySQL 8.0的LATERAL派生表也要能寫(xiě)。2.4 INT(5)不是限制只能存5位別再傳謠了“mysql中int5”這個(gè)搜索詞很有意思讓我想起一個(gè)流傳很久的誤解INT(5)不是“最多只能存5位整數(shù)”。括號(hào)里的數(shù)字是顯示寬度不是存儲(chǔ)范圍。存儲(chǔ)范圍只和類型本身有關(guān)類型占用字節(jié)有符號(hào)范圍TINYINT1-128 ~ 127SMALLINT2-32768 ~ 32767MEDIUMINT3-8388608 ~ 8388607INT4-2147483648 ~ 2147483647BIGINT8-9223372036854775808 ~ 9223372036854775807選型時(shí)按業(yè)務(wù)量級(jí)來(lái)狀態(tài)碼用TINYINT主鍵如果可能過(guò)億上BIGINT訂單金額如果涉及分和小數(shù)別直接用FLOAT/DOUBLE用DECIMAL。這屬于“學(xué)資料里看著不起眼、面試卻很愛(ài)問(wèn)”的細(xì)節(jié)。3. 讀執(zhí)行計(jì)劃是判斷“學(xué)明白”的分水嶺3.1 EXPLAIN結(jié)果到底看哪幾列“mysql explain詳解”被搜得這么頻繁說(shuō)明大家都知道執(zhí)行計(jì)劃重要但看的時(shí)候容易看懵。EXPLAIN輸出列很多核心就盯著五列type、key、rows、Extra、filtered。type是訪問(wèn)類型從差到好大致是ALL全表掃描、index掃整個(gè)索引樹(shù)、range索引范圍掃描、ref非唯一索引等值匹配、eq_ref唯一索引匹配、const主鍵或唯一索引等值匹配常數(shù)級(jí)別。拿到一條慢SQL先看type是不是ALL如果是大概率索引沒(méi)建對(duì)或者沒(méi)走到。rows是優(yōu)化器預(yù)估會(huì)掃描的行數(shù)數(shù)字越大越危險(xiǎn)。Extra里面出現(xiàn)Using filesort和Using temporary就要警惕了——前者意味著排序沒(méi)走索引MySQL要額外排序后者意味著用了臨時(shí)表通常和GROUP BY、DISTINCT有關(guān)。這兩個(gè)出現(xiàn)任何一個(gè)這條SQL都是重點(diǎn)優(yōu)化對(duì)象。3.2 一個(gè)慢SQL優(yōu)化的完整過(guò)程拿一個(gè)很典型的例子查某個(gè)用戶的訂單列表并按時(shí)間倒序。SELECT * FROM orders WHERE user_id 123 ORDER BY create_time DESC LIMIT 10;剛建表時(shí)只給主鍵加了個(gè)索引PRIMARY KEY(id)執(zhí)行計(jì)劃里type顯示ALLExtra顯示Using filesort掃描行數(shù)幾萬(wàn)。優(yōu)化方法很簡(jiǎn)單加一個(gè)聯(lián)合索引ALTER TABLE orders ADD INDEX idx_user_time (user_id, create_time);再EXPLAIN一遍type變成refrows變成個(gè)位數(shù)Using filesort消失。這里背后的原理是聯(lián)合索引(user_id, create_time)本身先按user_id排序、再按create_time排序等值條件定位到user_id后create_time天然就是有序的ORDER BY直接走索引。這類例子在“mysql執(zhí)行計(jì)劃”相關(guān)資料里反復(fù)出現(xiàn)但很多人看了就忘。我的建議是自己建一張十萬(wàn)行數(shù)據(jù)的測(cè)試表實(shí)際加索引前后各跑一遍EXPLAIN感受一次就記住了。3.3 加了索引也不一定快優(yōu)化器比你想的聰明很多新手遇到慢SQL就無(wú)腦加索引加了發(fā)現(xiàn)還是慢。原因有兩個(gè)第一索引區(qū)分度太低比如性別字段一個(gè)值對(duì)應(yīng)一半數(shù)據(jù)優(yōu)化器判斷走索引還不如全表掃描干脆放棄索引第二查詢條件里對(duì)索引列做了函數(shù)計(jì)算或隱式類型轉(zhuǎn)換索引會(huì)失效比如WHERE DATE(create_time) 2024-01-01應(yīng)該寫(xiě)成范圍條件WHERE create_time 2024-01-01 AND create_time 2024-01-02。判斷索引有沒(méi)有被用上除了看EXPLAIN還有一個(gè)命令SHOW INDEX FROM orders;看Cardinality這一列它表示索引中不同值的基數(shù)?;鶖?shù)太低優(yōu)化器自然看不上。4. 熱詞里出現(xiàn)頻率最高的幾個(gè)報(bào)錯(cuò)逐一交代排查鏈路4.1 ERROR 2002: Cant connect to local MySQL server through socket“error 2002 (hy000): cant connect to local mysql server through socket /var/...”這個(gè)報(bào)錯(cuò)在熱詞里出現(xiàn)了兩次可見(jiàn)有多少人卡在這一步。它的最直接原因就是客戶端連不到MySQL服務(wù)端。但具體哪一步斷了要按順序查服務(wù)到底有沒(méi)有啟動(dòng)服務(wù)啟動(dòng)后監(jiān)聽(tīng)的協(xié)議和路徑是什么客戶端連接時(shí)有沒(méi)有指定了不同的socket路徑Linux下先看進(jìn)程和端口ps aux | grep mysqld ss -lntp | grep 3306如果進(jìn)程沒(méi)起來(lái)去查錯(cuò)誤日志。如果進(jìn)程起來(lái)了但客戶端還是報(bào)socket錯(cuò)誤檢查/etc/my.cnf里的[mysqld]段有沒(méi)有指定socket /path/to/mysql.sock然后用mysql -S /path/to/mysql.sock去連。注意3306端口能通但報(bào)“Cant connect”通常是防火墻或bind-address配置問(wèn)題而報(bào)“through socket”則基本是本地連接路徑的問(wèn)題。先把兩個(gè)場(chǎng)景分開(kāi)。4.2 密碼忘了怎么辦“mysql密碼忘記了怎么辦”這種搜索詞一看就是真被卡住的人。不要急著重裝重置密碼的思路是臨時(shí)跳過(guò)權(quán)限表啟動(dòng)再登錄改密。以Linux為例sudo systemctl stop mysqld sudo mysqld_safe --skip-grant-tables mysql -u root進(jìn)入MySQL后FLUSH PRIVILEGES; ALTER USER rootlocalhost IDENTIFIED BY NewStrongPassword;然后重啟服務(wù)正常登錄。強(qiáng)調(diào)一個(gè)細(xì)節(jié)ALTER USER前先執(zhí)行FLUSH PRIVILEGES讓權(quán)限表先重新加載否則某些版本會(huì)報(bào)錯(cuò)。另外整個(gè)操作期間MySQL處于不設(shè)防狀態(tài)本地臨時(shí)搞沒(méi)問(wèn)題千萬(wàn)不能讓這個(gè)方式暴露到外網(wǎng)。4.3 Navicat連接失敗不只是密碼錯(cuò)的問(wèn)題“navicat連接mysql”這個(gè)熱詞背后九成是兩類問(wèn)題。第一類是8.0的認(rèn)證插件連不上上一節(jié)說(shuō)過(guò)。第二類是權(quán)限host問(wèn)題MySQL的賬號(hào)是“用戶名 host”兩個(gè)維度共同決定的新建用戶時(shí)如果寫(xiě)的是rootlocalhost那就只能從本機(jī)連遠(yuǎn)程連接要用root%或者單獨(dú)建一個(gè)navicat%賬號(hào)。排查命令SELECT user, host, plugin FROM mysql.user;看到root只有l(wèi)ocalhost就明白為什么遠(yuǎn)程連不上了。自己學(xué)習(xí)練手可以建一個(gè)專用賬號(hào)CREATE USER study% IDENTIFIED BY password; GRANT ALL PRIVILEGES ON *.* TO study%; FLUSH PRIVILEGES;4.4 鎖表和死鎖靠系統(tǒng)和日志線操作“mysql鎖表”這個(gè)熱詞很多人是帶著生產(chǎn)事故來(lái)搜的。癥狀是某條UPDATE或者SELECT一直卡住不動(dòng)時(shí)間長(zhǎng)了報(bào)Lock wait timeout exceeded。排查思路是找持有鎖的事務(wù)。直接查系統(tǒng)表SELECT * FROM information_schema.innodb_trx; SELECT * FROM information_schema.innodb_lock_waits;拿到trx_mysql_thread_id之后可以決定是否結(jié)束這個(gè)線程KILL 線程ID;日常開(kāi)發(fā)中鎖表的根源絕大多數(shù)是事務(wù)沒(méi)及時(shí)提交。InnoDB是行鎖鎖本身沒(méi)毛病毛病在于一個(gè)事務(wù)開(kāi)了多行更新中間還有別的交互操作一直不COMMIT或ROLLBACK鎖就越攢越多。所以寫(xiě)代碼的黃金規(guī)矩是事務(wù)要短別在事務(wù)里做網(wǎng)絡(luò)請(qǐng)求、文件IO這類耗時(shí)操作更新完數(shù)據(jù)立刻提交或回滾。5. 用面試題反推學(xué)習(xí)重點(diǎn)效率高很多5.1 高頻考點(diǎn)分布與優(yōu)先級(jí)“mysql面試題”被搜得很高頻我?guī)痛蠹野咽忻嫔铣R?jiàn)的考點(diǎn)歸一下類你會(huì)發(fā)現(xiàn)來(lái)來(lái)回回就這幾塊索引相關(guān)失效場(chǎng)景、最左前綴、回表、覆蓋索引執(zhí)行計(jì)劃EXPLAIN各列含義、慢SQL優(yōu)化事務(wù)隔離級(jí)別、MVCC、幻讀怎么解決的存儲(chǔ)引擎InnoDB和MyISAM的對(duì)比、鎖粒度存儲(chǔ)過(guò)程/函數(shù)基本語(yǔ)法、游標(biāo)、觸發(fā)器語(yǔ)法題行轉(zhuǎn)列、分組TopN、連續(xù)N天登錄運(yùn)維主從復(fù)制、日志類型、備份恢復(fù)我的建議是先搞懂InnoDB的行鎖和MVCC這兩塊是理解事務(wù)的基礎(chǔ)也是一堆面試題的源頭。然后再去刷索引優(yōu)化題最后再背語(yǔ)法題答案。順序反過(guò)來(lái)的話很容易變成“背了答案不知道在說(shuō)什么”面試官一追問(wèn)就露餡。5.2 Java對(duì)MySQL的“搜索語(yǔ)句”別只會(huì)LIKE %關(guān)鍵詞%熱詞里“java對(duì)mysql的搜索語(yǔ)句”用得不太嚴(yán)謹(jǐn)?shù)馑即蠹叶级贘ava業(yè)務(wù)代碼里查MySQL數(shù)據(jù)怎么寫(xiě)。最基礎(chǔ)的姿勢(shì)String sql SELECT * FROM articles WHERE title LIKE ?; PreparedStatement ps conn.prepareStatement(sql); ps.setString(1, % keyword %);兩個(gè)注意點(diǎn)。第一永遠(yuǎn)別用字符串拼接SQL用?占位符避免SQL注入第二前后都帶%的LIKE查詢索引基本走不了數(shù)據(jù)量大了會(huì)全表掃描。真正要做的搜索如果只是標(biāo)題、內(nèi)容的模糊匹配可以用MySQL全文索引FULLTEXT或者數(shù)據(jù)規(guī)模再大就交給專門(mén)的搜索引擎MySQL沒(méi)義務(wù)扛所有搜索壓力。5.3 以練代學(xué)的三個(gè)小項(xiàng)目只讀資料不動(dòng)手過(guò)兩個(gè)星期就忘。我建議按順序做三個(gè)練習(xí)做一個(gè)學(xué)生成績(jī)表寫(xiě)SQL查出每科前3名練窗口函數(shù)ROW_NUMBER做一個(gè)訂單表按月統(tǒng)計(jì)每個(gè)用戶的總金額再算月環(huán)比練窗口函數(shù)LAG、聚合、日期函數(shù)給一套慢SQL用EXPLAIN分析后加索引優(yōu)化對(duì)比前后執(zhí)行計(jì)劃練性能排查這三個(gè)都做完MySQL的基礎(chǔ)實(shí)戰(zhàn)能力基本就夠用了。6. 從單機(jī)學(xué)習(xí)到生產(chǎn)環(huán)境的最后一步6.1 唯一約束加不上是因?yàn)楸砝镆呀?jīng)有重復(fù)數(shù)據(jù)熱詞“mysql設(shè)置唯一已經(jīng)有重復(fù)數(shù)據(jù)庫(kù)”翻譯過(guò)來(lái)是想給某列加UNIQUE約束結(jié)果報(bào)錯(cuò)說(shuō)Duplicate entry。原因很簡(jiǎn)單列里已經(jīng)存在重復(fù)值了。加索引之前先查重復(fù)SELECT dup_col, COUNT(*) FROM your_table GROUP BY dup_col HAVING COUNT(*) 1;找到重復(fù)記錄后要么刪掉要么用業(yè)務(wù)邏輯去重確認(rèn)數(shù)據(jù)干凈了再執(zhí)行ALTER TABLE your_table ADD UNIQUE KEY uk_dup_col (dup_col);這個(gè)場(chǎng)景特別典型發(fā)生在“我先建表存數(shù)據(jù)后補(bǔ)約束”的開(kāi)發(fā)流程里。所以庫(kù)表設(shè)計(jì)階段就該把唯一鍵、外鍵、非空約束想清楚別等數(shù)據(jù)臟了再補(bǔ)。6.2 備份、遷移與常見(jiàn)同步需求搜“sqoop連接不上mysql”“domino用戶同步到mysql”“瀚高數(shù)據(jù)庫(kù)切換mysql模式”的人多半在做數(shù)據(jù)遷移或者異構(gòu)同步。這類需求的共性是不要一個(gè)SQL一個(gè)SQL去手改方言先把源庫(kù)和目標(biāo)庫(kù)的差異列成對(duì)照表。常見(jiàn)差異包括分頁(yè)寫(xiě)法不同MySQL用LIMITSQL Server用OFFSET FETCH、大小寫(xiě)敏感規(guī)則不同、內(nèi)置函數(shù)不同日期格式化、字符串拼接、自增列語(yǔ)法不同。摸清差異之后才能決定是寫(xiě)轉(zhuǎn)換腳本還是用同步工具。備份恢復(fù)這一塊也必須練別跳過(guò)mysqldump -u root -p --single-transaction your_db backup.sql mysql -u root -p your_db backup.sql--single-transaction加上之后InnoDB表在導(dǎo)出過(guò)程中不會(huì)鎖表對(duì)線上影響小。日常練習(xí)時(shí)把“備份→模擬誤刪→恢復(fù)”這套流程完整走一遍比背一百條命令都頂用。6.3 給自己立個(gè)“會(huì)用MySQL”的標(biāo)準(zhǔn)少聽(tīng)宣傳多看效果最后說(shuō)點(diǎn)個(gè)人的判斷標(biāo)準(zhǔn)。市面上“MySQL學(xué)習(xí)資料”太多了有大而全的教程也有各種面試題庫(kù)但學(xué)沒(méi)學(xué)會(huì)不是看資料收入了多少而是看能不能獨(dú)立完成三件事給定一張?jiān)O(shè)計(jì)合理的業(yè)務(wù)表和一坨真實(shí)SQL能不能用EXPLAIN把執(zhí)行計(jì)劃講清楚把慢SQL優(yōu)化到合理水平數(shù)據(jù)庫(kù)突然卡住或者報(bào)錯(cuò)能不能按日志和系統(tǒng)表一步步定位到根因線上要升級(jí)、要遷移、要恢復(fù)數(shù)據(jù)能不能在測(cè)試環(huán)境完整演練一遍。能做到這三條MySQL這塊就算真正落地了。資料永遠(yuǎn)只是地圖你能獨(dú)立走通的路才算自己的。我自己帶新人時(shí)見(jiàn)過(guò)太多“資料看了一堆一操作就卡殼”的情況所以如果你現(xiàn)在手上攢了好幾個(gè)版本的教程別急著都看完就從今天開(kāi)始先把MySQL裝上建一張表讀寫(xiě)幾個(gè)字段然后對(duì)照?qǐng)?zhí)行計(jì)劃把一條慢SQL改到跑得快——這一趟跑完你離“會(huì)用MySQL”就不遠(yuǎn)了。本文還有配套的精品資源點(diǎn)擊獲取