MySQL 一直是本人很薄弱的部分诈乒,后面會(huì)多輸出 MySQL 的文章貢獻(xiàn)給大家戏羽,畢竟 MySQL 涉及到數(shù)據(jù)存儲(chǔ)梧奢、鎖狱掂、磁盤尋道、分頁等操作系統(tǒng)概念亲轨,而且互聯(lián)網(wǎng)對(duì) MySQL 的注重程度是不言而喻的趋惨,后面要加緊對(duì) MySQL 的研究,寫的如果不好惦蚊,還請(qǐng)大家見諒希柿。
非關(guān)系型數(shù)據(jù)庫(kù)和關(guān)系型數(shù)據(jù)庫(kù)區(qū)別,優(yōu)勢(shì)比較
非關(guān)系型數(shù)據(jù)庫(kù)(感覺翻譯不是很準(zhǔn)確)稱為 NoSQL养筒,也就是 Not Only SQL曾撤,不僅僅是 SQL。非關(guān)系型數(shù)據(jù)庫(kù)不需要寫一些復(fù)雜的 SQL 語句晕粪,其內(nèi)部存儲(chǔ)方式是以 key-value 的形式存在可以把它想象成電話本的形式挤悉,每個(gè)人名(key)對(duì)應(yīng)電話(value)。常見的非關(guān)系型數(shù)據(jù)庫(kù)主要有 Hbase巫湘、Redis装悲、MongoDB 等。非關(guān)系型數(shù)據(jù)庫(kù)不需要經(jīng)過 SQL 的重重解析尚氛,所以性能很高诀诊;非關(guān)系型數(shù)據(jù)庫(kù)的可擴(kuò)展性比較強(qiáng),數(shù)據(jù)之間沒有耦合性阅嘶,遇見需要新加字段的需求属瓣,就直接增加一個(gè) key-value 鍵值對(duì)即可。
關(guān)系型數(shù)據(jù)庫(kù)以表格的形式存在讯柔,以行和列的形式存取數(shù)據(jù)抡蛙,關(guān)系型數(shù)據(jù)庫(kù)這一系列的行和列被稱為表,無數(shù)張表組成了數(shù)據(jù)庫(kù)魂迄,常見的關(guān)系型數(shù)據(jù)庫(kù)有 Oracle粗截、DB2、Microsoft SQL Server捣炬、MySQL等熊昌。關(guān)系型數(shù)據(jù)庫(kù)能夠支持復(fù)雜的 SQL 查詢,能夠體現(xiàn)出數(shù)據(jù)之間湿酸、表之間的關(guān)聯(lián)關(guān)系婿屹;關(guān)系型數(shù)據(jù)庫(kù)也支持事務(wù),便于提交或者回滾稿械。
它們之間的劣勢(shì)都是基于對(duì)方的優(yōu)勢(shì)來滿足的选泻。
MySQL 事務(wù)四大特性
一說到 MySQL 事務(wù),你肯定能想起來四大特性:原子性、一致性页眯、隔離性梯捕、持久性,下面再對(duì)這事務(wù)的四大特性做一個(gè)描述
原子性(Atomicity): 原子性指的就是 MySQL 中的包含事務(wù)的操作要么全部成功窝撵、要么全部失敗回滾傀顾,因此事務(wù)的操作如果成功就必須要全部應(yīng)用到數(shù)據(jù)庫(kù),如果操作失敗則不能對(duì)數(shù)據(jù)庫(kù)有任何影響碌奉。
這里涉及到一個(gè)概念短曾,什么是 MySQL 中的事務(wù)?事務(wù)是一組操作赐劣,組成這組操作的各個(gè)單元嫉拐,要不全都成功要不全都失敗,這個(gè)特性就是事務(wù)魁兼。在 MySQL 中婉徘,事務(wù)是在引擎層實(shí)現(xiàn)的,只有使用?innodb?引擎的數(shù)據(jù)庫(kù)或表才支持事務(wù)咐汞。
一致性(Consistency):一致性指的是一個(gè)事務(wù)在執(zhí)行前后其狀態(tài)一致盖呼。比如 A 和 B 加起來的錢一共是 1000 元,那么不管 A 和 B 之間如何轉(zhuǎn)賬化撕,轉(zhuǎn)多少次几晤,事務(wù)結(jié)束后兩個(gè)用戶的錢加起來還得是 1000,這就是事務(wù)的一致性植阴。
持久性(Durability): 持久性指的是一旦事務(wù)提交蟹瘾,那么發(fā)生的改變就是永久性的,即使數(shù)據(jù)庫(kù)遇到特殊情況比如故障的時(shí)候也不會(huì)產(chǎn)生干擾墙贱。
隔離性(Isolation):隔離性需要重點(diǎn)說一下热芹,當(dāng)多個(gè)事務(wù)同時(shí)進(jìn)行時(shí),就有可能出現(xiàn)臟讀(dirty read)惨撇、不可重復(fù)讀(non-repeatable read)、幻讀(phantom read) 的情況府寒,為了解決這些并發(fā)問題魁衙,提出了隔離性的概念。
臟讀:事務(wù) A 讀取了事務(wù) B 更新后的數(shù)據(jù)株搔,但是事務(wù) B 沒有提交剖淀,然后事務(wù) B 執(zhí)行回滾操作,那么事務(wù) A 讀到的數(shù)據(jù)就是臟數(shù)據(jù) 不可重復(fù)讀:事務(wù) A 進(jìn)行多次讀取操作纤房,事務(wù) B 在事務(wù) A 多次讀取的過程中執(zhí)行更新操作并提交纵隔,提交后事務(wù) A 讀到的數(shù)據(jù)不一致。 幻讀:事務(wù) A 將數(shù)據(jù)庫(kù)中所有學(xué)生的成績(jī)由 A -> B,此時(shí)事務(wù) B 手動(dòng)插入了一條成績(jī)?yōu)?A 的記錄捌刮,在事務(wù) A 更改完畢后碰煌,發(fā)現(xiàn)還有一條記錄沒有修改,那么這種情況就叫做出現(xiàn)了幻讀绅作。
SQL的隔離級(jí)別有四種芦圾,它們分別是讀未提交(read uncommitted)、讀已提交(read committed)俄认、可重復(fù)讀(repetable read) 和 串行化(serializable)个少。下面分別來解釋一下。
讀未提交:讀未提交指的是一個(gè)事務(wù)在提交之前眯杏,它所做的修改就能夠被其他事務(wù)所看到夜焦。
讀已提交:讀已提交指的是一個(gè)事務(wù)在提交之后,它所做的變更才能夠讓其他事務(wù)看到岂贩。
可重復(fù)讀:可重復(fù)讀指的是一個(gè)事務(wù)在執(zhí)行的過程中糊探,看到的數(shù)據(jù)是和啟動(dòng)時(shí)看到的數(shù)據(jù)是一致的。未提交的變更對(duì)其他事務(wù)不可見河闰。
串行化:顧名思義是對(duì)于同一行記錄科平,寫會(huì)加寫鎖,讀會(huì)加讀鎖姜性。當(dāng)出現(xiàn)讀寫鎖沖突的時(shí)候瞪慧,后訪問的事務(wù)必須等前一個(gè)事務(wù)執(zhí)行完成,才能繼續(xù)執(zhí)行部念。
這四個(gè)隔離級(jí)別可以解決臟讀弃酌、不可重復(fù)讀、幻象讀這三類問題儡炼〖讼妫總結(jié)如下
其中隔離級(jí)別由低到高是:讀未提交 < 讀已提交 < 可重復(fù)讀 < 串行化
隔離級(jí)別越高,越能夠保證數(shù)據(jù)的完整性和一致性乌询,但是對(duì)并發(fā)的性能影響越大榜贴。大多數(shù)數(shù)據(jù)庫(kù)的默認(rèn)級(jí)別是讀已提交(Read committed),比如 Sql Server妹田、Oracle 唬党,但是 MySQL 的默認(rèn)隔離級(jí)別是 可重復(fù)讀(repeatable-read)。
MySQL 常見存儲(chǔ)引擎的區(qū)別
MySQL 常見的存儲(chǔ)引擎鬼佣,可以使用
SHOW ENGINES
命令驶拱,來列出所有的存儲(chǔ)引擎
可以看到,InnoDB 是 MySQL 默認(rèn)支持的存儲(chǔ)引擎晶衷,支持事務(wù)蓝纲、行級(jí)鎖定和外鍵阴孟。
MyISAM 存儲(chǔ)引擎的特點(diǎn)
在 5.1 版本之前,MyISAM 是 MySQL 的默認(rèn)存儲(chǔ)引擎税迷,MyISAM 并發(fā)性比較差永丝,使用的場(chǎng)景比較少,主要特點(diǎn)是
不支持事務(wù)操作翁狐,ACID 的特性也就不存在了类溢,這一設(shè)計(jì)是為了性能和效率考慮的。
不支持外鍵操作露懒,如果強(qiáng)行增加外鍵闯冷,MySQL 不會(huì)報(bào)錯(cuò),只不過外鍵不起作用懈词。
MyISAM 默認(rèn)的鎖粒度是表級(jí)鎖蛇耀,所以并發(fā)性能比較差,加鎖比較快坎弯,鎖沖突比較少纺涤,不太容易發(fā)生死鎖的情況。
MyISAM 會(huì)在磁盤上存儲(chǔ)三個(gè)文件抠忘,文件名和表名相同撩炊,擴(kuò)展名分別是 .frm(存儲(chǔ)表定義)、.MYD(MYData,存儲(chǔ)數(shù)據(jù))崎脉、MYI(MyIndex,存儲(chǔ)索引)拧咳。這里需要特別注意的是 MyISAM 只緩存索引文件,并不緩存數(shù)據(jù)文件囚灼。
MyISAM 支持的索引類型有 全局索引(Full-Text)骆膝、B-Tree 索引、R-Tree 索引
Full-Text 索引:它的出現(xiàn)是為了解決針對(duì)文本的模糊查詢效率較低的問題灶体。
B-Tree 索引:所有的索引節(jié)點(diǎn)都按照平衡樹的數(shù)據(jù)結(jié)構(gòu)來存儲(chǔ)阅签,所有的索引數(shù)據(jù)節(jié)點(diǎn)都在葉節(jié)點(diǎn)
R-Tree索引:它的存儲(chǔ)方式和 B-Tree 索引有一些區(qū)別,主要設(shè)計(jì)用于存儲(chǔ)空間和多維數(shù)據(jù)的字段做索引,目前的 MySQL 版本僅支持 geometry 類型的字段作索引蝎抽,相對(duì)于 BTREE政钟,RTREE 的優(yōu)勢(shì)在于范圍查找。
數(shù)據(jù)庫(kù)所在主機(jī)如果宕機(jī)织中,MyISAM 的數(shù)據(jù)文件容易損壞锥涕,而且難以恢復(fù)。
增刪改查性能方面:SELECT 性能較高狭吼,適用于查詢較多的情況
InnoDB 存儲(chǔ)引擎的特點(diǎn)
自從 MySQL 5.1 之后,默認(rèn)的存儲(chǔ)引擎變成了 InnoDB 存儲(chǔ)引擎殖妇,相對(duì)于 MyISAM刁笙,InnoDB 存儲(chǔ)引擎有了較大的改變,它的主要特點(diǎn)是
支持事務(wù)操作,具有事務(wù) ACID 隔離特性疲吸,默認(rèn)的隔離級(jí)別是可重復(fù)讀(repetable-read)座每、通過MVCC(并發(fā)版本控制)來實(shí)現(xiàn)的。能夠解決臟讀和不可重復(fù)讀的問題摘悴。
InnoDB 支持外鍵操作峭梳。
InnoDB 默認(rèn)的鎖粒度行級(jí)鎖,并發(fā)性能比較好蹂喻,會(huì)發(fā)生死鎖的情況葱椭。
和 MyISAM 一樣的是,InnoDB 存儲(chǔ)引擎也有 .frm文件存儲(chǔ)表結(jié)構(gòu) 定義口四,但是不同的是孵运,InnoDB 的表數(shù)據(jù)與索引數(shù)據(jù)是存儲(chǔ)在一起的,都位于 B+ 數(shù)的葉子節(jié)點(diǎn)上蔓彩,而 MyISAM 的表數(shù)據(jù)和索引數(shù)據(jù)是分開的治笨。
InnoDB 有安全的日志文件,這個(gè)日志文件用于恢復(fù)因數(shù)據(jù)庫(kù)崩潰或其他情況導(dǎo)致的數(shù)據(jù)丟失問題赤嚼,保證數(shù)據(jù)的一致性旷赖。
InnoDB 和 MyISAM 支持的索引類型相同,但具體實(shí)現(xiàn)因?yàn)槲募Y(jié)構(gòu)的不同有很大差異更卒。
增刪改查性能方面等孵,果執(zhí)行大量的增刪改操作,推薦使用 InnoDB 存儲(chǔ)引擎逞壁,它在刪除操作時(shí)是對(duì)行刪除压鉴,不會(huì)重建表。
MyISAM 和 InnoDB 存儲(chǔ)引擎的對(duì)比
鎖粒度方面:由于鎖粒度不同未蝌,InnoDB 比 MyISAM 支持更高的并發(fā)樟遣;InnoDB 的鎖粒度為行鎖、MyISAM 的鎖粒度為表鎖姿骏、行鎖需要對(duì)每一行進(jìn)行加鎖糖声,所以鎖的開銷更大,但是能解決臟讀和不可重復(fù)讀的問題分瘦,相對(duì)來說也更容易發(fā)生死鎖
可恢復(fù)性上:由于 InnoDB 是有事務(wù)日志的蘸泻,所以在產(chǎn)生由于數(shù)據(jù)庫(kù)崩潰等條件后,可以根據(jù)日志文件進(jìn)行恢復(fù)嘲玫。而 MyISAM 則沒有事務(wù)日志悦施。
查詢性能上:MyISAM 要優(yōu)于 InnoDB,因?yàn)?InnoDB 在查詢過程中去团,是需要維護(hù)數(shù)據(jù)緩存抡诞,而且查詢過程是先定位到行所在的數(shù)據(jù)塊穷蛹,然后在從數(shù)據(jù)塊中定位到要查找的行;而 MyISAM 可以直接定位到數(shù)據(jù)所在的內(nèi)存地址昼汗,可以直接找到數(shù)據(jù)肴熏。
表結(jié)構(gòu)文件上: MyISAM 的表結(jié)構(gòu)文件包括:.frm(表結(jié)構(gòu)定義),.MYI(索引),.MYD(數(shù)據(jù));而 InnoDB 的表數(shù)據(jù)文件為:.ibd和.frm(表結(jié)構(gòu)定義)顷窒;
MySQL 基礎(chǔ)架構(gòu)
這道題應(yīng)該從 MySQL 架構(gòu)來理解蛙吏,我們可以把 MySQL 拆解成幾個(gè)零件,如下圖所示鞋吉。
大致上來說鸦做,MySQL 可以分為 Server層和 存儲(chǔ)引擎層。
Server 層包括連接器坯辩、查詢緩存馁龟、分析器、優(yōu)化器漆魔、執(zhí)行器坷檩,包括大多數(shù) MySQL 中的核心功能,所有跨存儲(chǔ)引擎的功能也在這一層實(shí)現(xiàn)改抡,包括 存儲(chǔ)過程矢炼、觸發(fā)器、視圖等阿纤。
存儲(chǔ)引擎層包括 MySQL 常見的存儲(chǔ)引擎句灌,包括 MyISAM、InnoDB 和 Memory 等欠拾,最常用的是 InnoDB胰锌,也是現(xiàn)在 MySQL 的默認(rèn)存儲(chǔ)引擎。存儲(chǔ)引擎也可以在創(chuàng)建表的時(shí)候手動(dòng)指定藐窄,比如下面资昧。
CREATE TABLE t (i INT) ENGINE = <Storage Engine>;
然后我們就可以探討 MySQL 的執(zhí)行過程了
首先需要在 MySQL 客戶端登陸才能使用,所以需要一個(gè)連接器來連接用戶和 MySQL 數(shù)據(jù)庫(kù)荆忍,我們一般是使用
mysql -u 用戶名 -p 密碼
來進(jìn)行 MySQL 登陸格带,和服務(wù)端建立連接。在完成 TCP 握手 后刹枉,連接器會(huì)根據(jù)你輸入的用戶名和密碼驗(yàn)證你的登錄身份叽唱。如果用戶名或者密碼錯(cuò)誤,MySQL 就會(huì)提示 Access denied for user微宝,來結(jié)束執(zhí)行棺亭。如果登錄成功后,MySQL 會(huì)根據(jù)權(quán)限表中的記錄來判定你的權(quán)限蟋软。
查詢緩存
連接完成后侦铜,你就可以執(zhí)行 SQL 語句了专甩,這行邏輯就會(huì)來到第二步:查詢緩存钟鸵。
MySQL 在得到一個(gè)執(zhí)行請(qǐng)求后钉稍,會(huì)首先去 查詢緩存 中查找,是否執(zhí)行過這條 SQL 語句棺耍,之前執(zhí)行過的語句以及結(jié)果會(huì)以 key-value 對(duì)的形式贡未,被直接放在內(nèi)存中。key 是查詢語句蒙袍,value 是查詢的結(jié)果俊卤。如果通過 key 能夠查找到這條 SQL 語句,就直接返回 SQL 的執(zhí)行結(jié)果害幅。
如果語句不在查詢緩存中消恍,就會(huì)繼續(xù)后面的執(zhí)行階段。執(zhí)行完成后以现,執(zhí)行結(jié)果就會(huì)被放入查詢緩存中狠怨。可以看到邑遏,如果查詢命中緩存佣赖,MySQL 不需要執(zhí)行后面的復(fù)雜操作,就可以直接返回結(jié)果记盒,效率會(huì)很高憎蛤。
但是查詢緩存不建議使用
為什么呢?因?yàn)橹灰?MySQL 中對(duì)某一張表執(zhí)行了更新操作纪吮,那么所有的查詢緩存就會(huì)失效俩檬,對(duì)于更新頻繁的數(shù)據(jù)庫(kù)來說,查詢緩存的命中率很低碾盟。
分析器
如果沒有命中查詢棚辽,就開始執(zhí)行真正的 SQL 語句。
首先巷疼,MySQL 會(huì)根據(jù)你寫的 SQL 語句進(jìn)行解析晚胡,分析器會(huì)先做 詞法分析,你寫的 SQL 就是由多個(gè)字符串和空格組成的一條 SQL 語句嚼沿,MySQL 需要識(shí)別出里面的字符串是什么估盘,代表什么。
然后進(jìn)行 語法分析骡尽,根據(jù)詞法分析的結(jié)果遣妥, 語法分析器會(huì)根據(jù)語法規(guī)則,判斷你輸入的這個(gè) SQL 語句是否滿足 MySQL 語法攀细。如果 SQL 語句不正確箫踩,就會(huì)提示 You have an error in your SQL syntax爱态。
優(yōu)化器
經(jīng)過分析器的詞法分析和語法分析后,你這條 SQL 就合法了境钟,MySQL 就知道你要做什么了锦担。但是在執(zhí)行前,還需要進(jìn)行優(yōu)化器的處理慨削,優(yōu)化器會(huì)判斷你使用了哪種索引洞渔,使用了何種連接,優(yōu)化器的作用就是確定效率最高的執(zhí)行方案缚态。
執(zhí)行器
MySQL 通過分析器知道了你的 SQL 語句是否合法磁椒,你想要做什么操作,通過優(yōu)化器知道了該怎么做效率最高玫芦,然后就進(jìn)入了執(zhí)行階段浆熔,開始執(zhí)行這條 SQL 語句
在執(zhí)行階段,MySQL 首先會(huì)判斷你有沒有執(zhí)行這條語句的權(quán)限桥帆,沒有權(quán)限的話医增,就會(huì)返回沒有權(quán)限的錯(cuò)誤。如果有權(quán)限环葵,就打開表繼續(xù)執(zhí)行调窍。打開表的時(shí)候,執(zhí)行器就會(huì)根據(jù)表的引擎定義张遭,去使用這個(gè)引擎提供的接口邓萨。對(duì)于有索引的表,執(zhí)行的邏輯也差不多菊卷。
至此缔恳,MySQL 對(duì)于一條語句的執(zhí)行過程也就完成了。
SQL 的執(zhí)行順序
我們?cè)诰帉懸粋€(gè)查詢語句的時(shí)候
SELECT DISTINCT < select_list > FROM < left_table > < join_type > JOIN < right_table > ON < join_condition > WHERE < where_condition > GROUP BY < group_by_list > HAVING < having_condition > ORDER BY < order_by_condition > LIMIT < limit_number >
它的執(zhí)行順序你知道嗎洁闰?這道題就給你一個(gè)回答歉甚。
首先,對(duì) SELECT 語句執(zhí)行查詢時(shí)扑眉,對(duì)FROM?關(guān)鍵字兩邊的表執(zhí)行連接纸泄,會(huì)形成笛卡爾積,這時(shí)候會(huì)產(chǎn)生一個(gè)虛表VT1(virtual table)
首先先來解釋一下什么是笛卡爾積
現(xiàn)在我們有兩個(gè)集合 A = {0,1} , B = {2,3,4}
那么腰素,集合 A * B 得到的結(jié)果就是
A * B = {(0,2)聘裁、(1,2)、(0,3)弓千、(1,3)衡便、(0,4)、(1,4)};
B * A = {(2,0)、{2,1}镣陕、{3,0}谴餐、{3,1}、{4,0}呆抑、(4,1)};
上面 A * B 和 B * A 的結(jié)果就可以稱為兩個(gè)集合相乘的 笛卡爾積
我們可以得出結(jié)論岂嗓,A 集合和 B 集合相乘,包含了集合 A 中的元素和集合 B 中元素之和理肺,也就是 A 元素的個(gè)數(shù) * B 元素的個(gè)數(shù)
再來解釋一下什么是虛表
在 MySQL 中摄闸,有三種類型的表 一種是永久表,永久表就是創(chuàng)建以后用來長(zhǎng)期保存數(shù)據(jù)的表 一種是臨時(shí)表妹萨,臨時(shí)表也有兩類,一種是和永久表一樣炫欺,只保存臨時(shí)數(shù)據(jù)乎完,但是能夠長(zhǎng)久存在的;還有一種是臨時(shí)創(chuàng)建的品洛,SQL 語句執(zhí)行完成就會(huì)刪除树姨。 一種是虛表,虛表其實(shí)就是視圖桥状,數(shù)據(jù)可能會(huì)來自多張表的執(zhí)行結(jié)果帽揪。
ON 過濾
然后對(duì) FROM 連接的結(jié)果進(jìn)行 ON 篩選,創(chuàng)建 VT2辅斟,把符合記錄的條件存在 VT2 中转晰。
JOIN 連接
第三步,如果是 OUTER JOIN(left join士飒、right join) 查邢,那么這一步就將添加外部行,如果是 left join 就把 ON 過濾條件的左表添加進(jìn)來酵幕,如果是 right join 扰藕,就把右表添加進(jìn)來,從而生成新的虛擬表 VT3芳撒。
WHERE 過濾
第四步邓深,是執(zhí)行 WHERE 過濾器,對(duì)上一步生產(chǎn)的虛擬表引用 WHERE 篩選笔刹,生成虛擬表 VT4芥备。
WHERE 和 ON 的區(qū)別
如果有外部列,ON 針對(duì)過濾的是關(guān)聯(lián)表徘熔,主表(保留表)會(huì)返回所有的列;
如果沒有添加外部列门躯,兩者的效果是一樣的;
應(yīng)用
對(duì)主表的過濾應(yīng)該使用 WHERE;
對(duì)于關(guān)聯(lián)表,先條件查詢后連接則用 ON酷师,先連接后條件查詢則用 WHERE;
GROUP BY
根據(jù) group by 字句中的列讶凉,會(huì)對(duì) VT4 中的記錄進(jìn)行分組操作染乌,產(chǎn)生虛擬機(jī)表 VT5。果應(yīng)用了group by懂讯,那么后面的所有步驟都只能得到的 VT5 的列或者是聚合函數(shù)(count荷憋、sum、avg等)褐望。
HAVING
緊跟著 GROUP BY 字句后面的是 HAVING勒庄,使用 HAVING 過濾,會(huì)把符合條件的放在 VT6
SELECT
第七步才會(huì)執(zhí)行 SELECT 語句瘫里,將 VT6 中的結(jié)果按照 SELECT 進(jìn)行刷選实蔽,生成 VT7
DISTINCT
在第八步中,會(huì)對(duì) TV7 生成的記錄進(jìn)行去重操作谨读,生成 VT8局装。事實(shí)上如果應(yīng)用了 group by 子句那么 distinct 是多余的,原因同樣在于劳殖,分組的時(shí)候是將列中唯一的值分成一組铐尚,同時(shí)只為每一組返回一行記錄,那么所以的記錄都將是不相同的哆姻。
ORDER BY
應(yīng)用 order by 子句宣增。按照 order_by_condition 排序 VT8,此時(shí)返回的一個(gè)游標(biāo)矛缨,而不是虛擬表爹脾。sql 是基于集合的理論的,集合不會(huì)預(yù)先對(duì)他的行排序劳景,它只是成員的邏輯集合誉简,成員的順序是無關(guān)緊要的。
SQL 語句執(zhí)行的過程如下
什么是臨時(shí)表盟广,何時(shí)刪除臨時(shí)表
什么是臨時(shí)表闷串?MySQL 在執(zhí)行 SQL 語句的過程中,通常會(huì)臨時(shí)創(chuàng)建一些存儲(chǔ)中間結(jié)果集的表筋量,臨時(shí)表只對(duì)當(dāng)前連接可見烹吵,在連接關(guān)閉時(shí),臨時(shí)表會(huì)被刪除并釋放所有表空間桨武。
臨時(shí)表分為兩種:一種是內(nèi)存臨時(shí)表肋拔,一種是磁盤臨時(shí)表,什么區(qū)別呢呀酸??jī)?nèi)存臨時(shí)表使用的是 MEMORY 存儲(chǔ)引擎凉蜂,而臨時(shí)表采用的是 MyISAM 存儲(chǔ)引擎。
MEMORY 存儲(chǔ)引擎:memory 是 MySQL 中一類特殊的存儲(chǔ)引擎,它使用存儲(chǔ)在內(nèi)容中的內(nèi)容來創(chuàng)建表窿吩,而且數(shù)據(jù)全部放在內(nèi)存中茎杂。每個(gè)基于 MEMORY 存儲(chǔ)引擎的表實(shí)際對(duì)應(yīng)一個(gè)磁盤文件。該文件的文件名與表名相同纫雁,類型為 frm 類型煌往。而其數(shù)據(jù)文件,都是存儲(chǔ)在內(nèi)存中轧邪,這樣有利于數(shù)據(jù)的快速處理刽脖,提高整個(gè)表的效率。MEMORY 用到的很少忌愚,因?yàn)樗前褦?shù)據(jù)存到內(nèi)存中曲管,如果內(nèi)存出現(xiàn)異常就會(huì)影響數(shù)據(jù)。如果重啟或者關(guān)機(jī)菜循,所有數(shù)據(jù)都會(huì)消失翘地。因此,基于 MEMORY 的表的生命周期很短癌幕,一般是一次性的。
MySQL 會(huì)在下面這幾種情況產(chǎn)生臨時(shí)表
使用 UNION 查詢:UNION 有兩種昧穿,一種是UNION 勺远,一種是 UNION ALL ,它們都用于聯(lián)合查詢时鸵;區(qū)別是 使用 UNION 會(huì)去掉兩個(gè)表中的重復(fù)數(shù)據(jù)胶逢,相當(dāng)于對(duì)結(jié)果集做了一下去重(distinct)。使用 UNION ALL饰潜,則不會(huì)排重初坠,返回所有的行。使用 UNION 查詢會(huì)產(chǎn)生臨時(shí)表彭雾。
使用 TEMPTABLE 算法或者是 UNION 查詢中的視圖碟刺。TEMPTABLE 算法是一種創(chuàng)建臨時(shí)表的算法,它是將結(jié)果放置到臨時(shí)表中薯酝,意味這要 MySQL 要先創(chuàng)建好一個(gè)臨時(shí)表半沽,然后將結(jié)果放到臨時(shí)表中去,然后再使用這個(gè)臨時(shí)表進(jìn)行相應(yīng)的查詢吴菠。
ORDER BY 和 GROUP BY 的子句不一樣時(shí)也會(huì)產(chǎn)生臨時(shí)表者填。
DISTINCT 查詢并且加上 ORDER BY 時(shí);
SQL中用到 SQL_SMALL_RESULT 選項(xiàng)時(shí)做葵;如果查詢結(jié)果比較小的時(shí)候占哟,可以加上 SQL_SMALL_RESULT 來優(yōu)化,產(chǎn)生臨時(shí)表
FROM 中的子查詢;
EXPLAIN 查看執(zhí)行計(jì)劃結(jié)果的 Extra 列中榨乎,如果使用 Using Temporary 就表示會(huì)用到臨時(shí)表怎燥。
MySQL 常見索引類型
索引是存儲(chǔ)在一張表中特定列上的數(shù)據(jù)結(jié)構(gòu),索引是在列上創(chuàng)建的谬哀。并且刺覆,索引是一種數(shù)據(jù)結(jié)構(gòu)。
在 MySQL 中史煎,主要有下面這幾種索引
全局索引(FULLTEXT):全局索引谦屑,目前只有 MyISAM 引擎支持全局索引,它的出現(xiàn)是為了解決針對(duì)文本的模糊查詢效率較低的問題篇梭。
哈希索引(HASH):哈希索引是 MySQL 中用到的唯一 key-value 鍵值對(duì)的數(shù)據(jù)結(jié)構(gòu)氢橙,很適合作為索引。HASH 索引具有一次定位的好處恬偷,不需要像樹那樣逐個(gè)節(jié)點(diǎn)查找悍手,但是這種查找適合應(yīng)用于查找單個(gè)鍵的情況,對(duì)于范圍查找袍患,HASH 索引的性能就會(huì)很低坦康。
B-Tree 索引:B 就是 Balance 的意思,BTree 是一種平衡樹诡延,它有很多變種滞欠,最常見的就是 B+ Tree,它被 MySQL 廣泛使用肆良。
R-Tree 索引:R-Tree 在 MySQL 很少使用筛璧,僅支持 geometry 數(shù)據(jù)類型,支持該類型的存儲(chǔ)引擎只有MyISAM惹恃、BDb夭谤、InnoDb、NDb巫糙、Archive幾種朗儒,相對(duì)于 B-Tree 來說,R-Tree 的優(yōu)勢(shì)在于范圍查找曲秉。
varchar 和 char 的區(qū)別和使用場(chǎng)景
MySQL 中沒有 nvarchar 數(shù)據(jù)類型采蚀,所以直接比較的是 varchar 和 char 的區(qū)別
char :表示的是定長(zhǎng)的字符串,當(dāng)你輸入小于指定的數(shù)目承二,比如你指定的數(shù)目是 char(6)榆鼠,當(dāng)你輸入小于 6 個(gè)字符的時(shí)候,char 會(huì)在你最后一個(gè)字符后面補(bǔ)空值亥鸠。當(dāng)你輸入超過指定允許最大長(zhǎng)度后妆够,MySQL 會(huì)報(bào)錯(cuò)
varchar: varchar 指的是長(zhǎng)度為 n 個(gè)字節(jié)的可變長(zhǎng)度识啦,并且是非Unicode的字符數(shù)據(jù)。n 的值是介于 1 - 8000 之間的數(shù)值神妹。存儲(chǔ)大小為實(shí)際大小颓哮。
Unicode 是一種字符編碼方案,它為每種語言中的每個(gè)字符都設(shè)定了統(tǒng)一唯一的二進(jìn)制編碼鸵荠,以實(shí)現(xiàn)跨語言冕茅、跨平臺(tái)進(jìn)行文本轉(zhuǎn)換、處理的要求
使用 char 存儲(chǔ)定長(zhǎng)的數(shù)據(jù)非常方便蛹找、char 檢索效率高姨伤,無論你存儲(chǔ)的數(shù)據(jù)是否到了 10 個(gè)字節(jié),都要去占用 10 字節(jié)的空間
使用 varchar 可以存儲(chǔ)變長(zhǎng)的數(shù)據(jù)庸疾,但存儲(chǔ)效率沒有 char 高乍楚。
什么是 內(nèi)連接、外連接届慈、交叉連接徒溪、笛卡爾積
連接的方式主要有三種:外連接、內(nèi)鏈接金顿、交叉連接
外連接(OUTER JOIN):外連接分為三種臊泌,分別是左外連接(LEFT OUTER JOIN 或 LEFT JOIN) 、右外連接(RIGHT OUTER JOIN 或 RIGHT JOIN) 揍拆、全外連接(FULL OUTER JOIN 或 FULL JOIN)
左外連接:又稱為左連接缺虐,這種連接方式會(huì)顯示左表不符合條件的數(shù)據(jù)行,右邊不符合條件的數(shù)據(jù)行直接顯示 NULL
右外連接:也被稱為右連接礁凡,他與左連接相對(duì),這種連接方式會(huì)顯示右表不符合條件的數(shù)據(jù)行慧妄,左表不符合條件的數(shù)據(jù)行直接顯示 NULL
MySQL 暫不支持全外連接
內(nèi)連接(INNER JOIN):結(jié)合兩個(gè)表中相同的字段顷牌,返回關(guān)聯(lián)字段相符的記錄。
笛卡爾積(Cartesian product): 我在上面提到了笛卡爾積塞淹,為了方便窟蓝,下面再列出來一下。
現(xiàn)在我們有兩個(gè)集合 A = {0,1} , B = {2,3,4} 那么饱普,集合 A * B 得到的結(jié)果就是 A * B = {(0,2)运挫、(1,2)、(0,3)套耕、(1,3)谁帕、(0,4)、(1,4)}; B * A = {(2,0)冯袍、{2,1}匈挖、{3,0}碾牌、{3,1}、{4,0}儡循、(4,1)}; 上面 A * B 和 B * A 的結(jié)果就可以稱為兩個(gè)集合相乘的 笛卡爾積 我們可以得出結(jié)論舶吗,A 集合和 B 集合相乘,包含了集合 A 中的元素和集合 B 中元素之和择膝,也就是 A 元素的個(gè)數(shù) * B 元素的個(gè)數(shù) .
交叉連接的原文是Cross join 誓琼,就是笛卡爾積在 SQL 中的實(shí)現(xiàn),SQL中使用關(guān)鍵字CROSS JOIN來表示交叉連接肴捉,在交叉連接中腹侣,隨便增加一個(gè)表的字段,都會(huì)對(duì)結(jié)果造成很大的影響每庆。
SELECT * FROM t_Class a CROSS JOIN t_Student b WHERE a.classid=b.classid
1
或者不用 CROSS JOIN筐带,直接用 FROM 也能表示交叉連接的效果
SELECT * FROM t_Class a ,t_Student b WHERE a.classid=b.classid
1
如果表中字段比較多,不適宜用交叉連接缤灵,交叉連接的效率比較差伦籍。
全連接:全連接也就是 full join,MySQL 中不支持全連接,但是可以使用其他連接查詢來模擬全連接,可以使用 UNION 和 UNION ALL 進(jìn)行模擬族奢。例如
(select colum1,colum2...columN from tableA ) union (select colum1,colum2...columN from tableB ) 或 (select colum1,colum2...columN from tableA ) union all (select colum1,colum2...columN from tableB )责循;
使用 UNION 和 UNION ALL 的注意事項(xiàng)
通過 union 連接的 SQL 分別單獨(dú)取出的列數(shù)必須相同
使用 union 時(shí),多個(gè)相等的行將會(huì)被合并饭于,由于合并比較耗時(shí),一般不直接使用 union 進(jìn)行合并,而是通常采用 union all 進(jìn)行合并
談?wù)?SQL 優(yōu)化的經(jīng)驗(yàn)
查詢語句無論是使用哪種判斷條件 等于攻锰、小于、大于妓雾, WHERE 左側(cè)的條件查詢字段不要使用函數(shù)或者表達(dá)式
使用 EXPLAIN 命令優(yōu)化你的 SELECT 查詢娶吞,對(duì)于復(fù)雜、效率低的 sql 語句械姻,我們通常是使用 explain sql 來分析這條 sql 語句妒蛇,這樣方便我們分析,進(jìn)行優(yōu)化楷拳。
當(dāng)你的 SELECT 查詢語句只需要使用一條記錄時(shí)绣夺,要使用 LIMIT 1
不要直接使用 SELECT *,而應(yīng)該使用具體需要查詢的表字段欢揖,因?yàn)槭褂?EXPLAIN 進(jìn)行分析時(shí)陶耍,SELECT * 使用的是全表掃描,也就是 type = all浸颓。
為每一張表設(shè)置一個(gè) ID 屬性
避免在 WHERE 字句中對(duì)字段進(jìn)行 NULL 判斷
避免在 WHERE 中使用 != 或 <> 操作符
使用 BETWEEN AND 替代 IN
為搜索字段創(chuàng)建索引
選擇正確的存儲(chǔ)引擎物臂,InnoDB 旺拉、MyISAM 、MEMORY 等
使用 LIKE %abc% 不會(huì)走索引棵磷,而使用 LIKE abc% 會(huì)走索引
對(duì)于枚舉類型的字段(即有固定羅列值的字段)蛾狗,建議使用ENUM而不是VARCHAR,如性別仪媒、星期沉桌、類型、類別等
拆分大的 DELETE 或 INSERT 語句
選擇合適的字段類型算吩,選擇標(biāo)準(zhǔn)是 盡可能小留凭、盡可能定長(zhǎng)、盡可能使用整數(shù)偎巢。
字段設(shè)計(jì)盡可能使用 NOT NULL
進(jìn)行水平切割或者垂直分割
水平分割:通過建立結(jié)構(gòu)相同的幾張表分別存儲(chǔ)數(shù)據(jù)
垂直分割:將經(jīng)常一起使用的字段放在一個(gè)單獨(dú)的表中蔼夜,分割后的表記錄之間是一一對(duì)應(yīng)關(guān)系。