目錄
(1)非關係型數據庫和關係型數據庫區別,優勢比較
非關係型數據庫(感覺翻譯不是很準確)稱爲 NoSQL
,也就是 Not Only SQL,不僅僅是 SQL。非關係型數據庫不需要寫一些複雜的 SQL 語句,其內部存儲方式是以 key-value
的形式存在可以把它想象成電話本的形式, 常見的非關係型數據庫主要有 Hbase、Redis、MongoDB 等。非關係型數據庫不需要經過 SQL 的重重解析,所以性能很高;非關係型數據庫的可擴展性比較強,數據之間沒有耦合性,遇見需要新加字段的需求,就直接增加一個 key-value 鍵值對即可。
(2)MySQL 事務四大特性
原子性(Atomicity)
: 原子性指的就是 MySQL 中的包含事務的操作要麼全部成功
、要麼全部失敗回滾
,因此事務的操作如果成功就必須要全部應用到數據庫,如果操作失敗則不能對數據庫有任何影響。一致性(Consistency)
:一致性指的是一個事務在執行前後其狀態一致。比如 A 和 B 加起來的錢一共是 1000 元,那麼不管 A 和 B 之間如何轉賬,轉多少次,事務結束後兩個用戶的錢加起來還得是 1000,這就是事務的一致性。持久性(Durability)
: 持久性指的是一旦事務提交,那麼發生的改變就是永久性的,即使數據庫遇到特殊情況比如故障的時候也不會產生干擾。隔離性(Isolation)
:隔離性需要重點說一下,當多個事務同時進行時,就有可能出現髒讀(dirty read)
、不可重複讀(non-repeatable read)
、幻讀(phantom read)
的情況,爲了解決這些併發問題,提出了隔離性的概念。
(3)SQL的隔離級別
- 讀未提交:讀未提交指的是一個事務在提交之前,它所做的修改就能夠被其他事務所看到。
- 讀已提交:讀已提交指的是一個事務在提交之後,它所做的變更才能夠讓其他事務看到。
- 可重複讀:可重複讀指的是一個事務在執行的過程中,看到的數據是和啓動時看到的數據是一致的。未提交的變更對其他事務不可見。
- 串行化:顧名思義是對於同一行記錄,
寫
會加寫鎖
,讀
會加讀鎖
。當出現讀寫鎖衝突的時候,後訪問的事務必須等前一個事務執行完成,才能繼續執行。
大多數數據庫的默認級別是讀已提交(Read committed)
,比如 Sql Server、Oracle ,但是 MySQL 的默認隔離級別是 可重複讀(repeatable-read)
。
(4)MySQL 常見存儲引擎的區別
SHOW ENGINES
可以看到,InnoDB 是 MySQL 默認支持的存儲引擎,支持事務、行級鎖定和外鍵。
- MyISAM 存儲引擎的特點
- 不支持
事務
操作 - 不支持
外鍵
操作,如果強行增加外鍵,MySQL 不會報錯,只不過外鍵不起作用 - MyISAM 默認的鎖粒度是
表級鎖
,所以併發性能比較差,加鎖比較快,鎖衝突比較少,不太容易發生死鎖的情況。 - MyISAM 會在磁盤上存儲三個文件,文件名和表名相同,擴展名分別是
.frm(存儲表定義)
、.MYD(MYData,存儲數據)
、MYI(MyIndex,存儲索引)
。這裏需要特別注意的是 MyISAM 只緩存索引文件
,並不緩存數據文件 - MyISAM 支持的索引類型有
全局索引(Full-Text)
、B-Tree 索引
、R-Tree 索引
- 數據庫所在主機如果宕機,MyISAM 的數據文件容易損壞,而且難以恢復
- 增刪改查性能方面:SELECT 性能較高,適用於查詢較多的情況
-
InnoDB 存儲引擎的特點
- 支持事務操作,具有事務 ACID 隔離特性,默認的隔離級別是
可重複讀(repetable-read)
、通過MVCC(併發版本控制)來實現的。能夠解決髒讀
和不可重複讀
的問題。 -
InnoDB 支持外鍵操作。
-
InnoDB 默認的鎖粒度
行級鎖
,併發性能比較好,會發生死鎖的情況。 -
InnoDB 有安全的日誌文件,這個日誌文件用於恢復因數據庫崩潰或其他情況導致的數據丟失問題,保證數據的一致性。
(5)MyISAM 和 InnoDB 存儲引擎的對比
鎖粒度方面
:由於鎖粒度不同,InnoDB 比 MyISAM 支持更高的併發;InnoDB 的鎖粒度爲行鎖、MyISAM 的鎖粒度爲表鎖、行鎖需要對每一行進行加鎖,所以鎖的開銷更大,但是能解決髒讀和不可重複讀的問題,相對來說也更容易發生死鎖可恢復性上
:由於 InnoDB 是有事務日誌的,所以在產生由於數據庫崩潰等條件後,可以根據日誌文件進行恢復。而 MyISAM 則沒有事務日誌。查詢性能上
:MyISAM 要優於 InnoDB,因爲 InnoDB 在查詢過程中,是需要維護數據緩存,而且查詢過程是先定位到行所在的數據塊,然後在從數據塊中定位到要查找的行;而 MyISAM 可以直接定位到數據所在的內存地址,可以直接找到數據。表結構文件上
:MyISAM 的表結構文件包括:.frm(表結構定義),.MYI(索引),.MYD(數據);而 InnoDB 的表數據文件爲:.ibd和.frm(表結構定義);
(6)MySQL 基礎架構
MySQL 可以分爲 Server
層和 存儲引擎
層
-
Server 層包括連接器、查詢緩存、分析器、優化器、執行器,包括大多數 MySQL 中的核心功能,所有跨存儲引擎的功能也在這一層實現,包括 存儲過程、觸發器、視圖等。
-
存儲引擎層包括 MySQL 常見的存儲引擎,包括 MyISAM、InnoDB 和 Memory 等,最常用的是 InnoDB,也是現在 MySQL 的默認存儲引擎。存儲引擎也可以在創建表的時候手動指定,比如下面
CREATE TABLE t (i INT) ENGINE = <Storage Engine>;
-
連接器
mysql -u 用戶名 -p 密碼
來進行 MySQL 登陸,和服務端建立連接。在完成 TCP 握手
後,連接器會根據你輸入的用戶名和密碼驗證你的登錄身份。
2.查詢緩存
連接完成後,你就可以執行 SQL 語句了,這行邏輯就會來到第二步:查詢緩存
但是查詢緩存不建議使用
爲什麼呢?因爲只要在 MySQL 中對某一張表執行了更新操作,那麼所有的查詢緩存就會失效,對於更新頻繁的數據庫來說,查詢緩存的命中率很低。
分析器
如果沒有命中查詢,就開始執行真正的 SQL 語句。
-
首先,MySQL 會根據你寫的 SQL 語句進行解析,分析器會先做
詞法分析
,你寫的 SQL 就是由多個字符串和空格組成的一條 SQL 語句,MySQL 需要識別出裏面的字符串是什麼,代表什麼。 -
然後進行
語法分析
,根據詞法分析的結果, 語法分析器會根據語法規則,判斷你輸入的這個 SQL 語句是否滿足 MySQL 語法。如果 SQL 語句不正確,就會提示 You have an error in your SQL syntax
(7)SQL 的執行順序
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 >
-
FROM 連接
首先,對 SELECT 語句執行查詢時,對
FROM
關鍵字兩邊的表執行連接,會形成笛卡爾積
,這時候會產生一個虛表VT1(virtual table)
首先先來解釋一下什麼是
笛卡爾積
現在我們有兩個集合 A = {0,1} , B = {2,3,4},那麼,集合 A * B 得到的結果就是
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 的結果就可以稱爲兩個集合相乘的
笛卡爾積
我們可以得出結論,A 集合和 B 集合相乘,包含了集合 A 中的元素和集合 B 中元素之和,也就是 A 元素的個數 * B 元素的個數
-
ON 過濾
然後對 FROM 連接的結果進行 ON 篩選,創建 VT2,把符合記錄的條件存在 VT2 中。
-
JOIN 連接
第三步,如果是 OUTER JOIN(left join、right join)
,那麼這一步就將添加外部行,如果是 left join 就把 ON 過濾條件的左表添加進來,如果是 right join ,就把右表添加進來,從而生成新的虛擬表 VT3。
-
WHERE 過濾
第四步,是執行 WHERE 過濾器,對上一步生產的虛擬表引用 WHERE 篩選,生成虛擬表 VT4。
WHERE 和 ON 的區別
如果有外部列,ON 針對過濾的是關聯表,主表(保留表)會返回所有的列;
如果沒有添加外部列,兩者的效果是一樣的;
應用
對主表的過濾應該使用 WHERE;
對於關聯表,先條件查詢後連接則用 ON,先連接後條件查詢則用 WHERE;
-
GROUP BY
根據 group by 字句中的列,會對 VT4 中的記錄進行分組操作,產生虛擬機表 VT5。果應用了group by,那麼後面的所有步驟都只能得到的 VT5 的列或者是聚合函數(count、sum、avg等)。
-
HAVING
緊跟着 GROUP BY 字句後面的是 HAVING,使用 HAVING 過濾,會把符合條件的放在 VT6
-
SELECT
第七步纔會執行 SELECT 語句,將 VT6 中的結果按照 SELECT 進行刷選,生成 VT7
-
DISTINCT
在第八步中,會對 TV7 生成的記錄進行去重操作,生成 VT8。事實上如果應用了 group by 子句那麼 distinct 是多餘的,原因同樣在於,分組的時候是將列中唯一的值分成一組,同時只爲每一組返回一行記錄,那麼所以的記錄都將是不相同的。
-
ORDER BY
應用 order by 子句。按照 order_by_condition 排序 VT8,此時返回的一個遊標,而不是虛擬表。sql 是基於集合的理論的,集合不會預先對他的行排序,它只是成員的邏輯集合,成員的順序是無關緊要的。
SQL 語句執行的過程如下
(7)什麼是臨時表,何時刪除臨時表
什麼是臨時表?MySQL 在執行 SQL 語句的過程中,通常會臨時創建一些存儲中間結果集
的表,臨時表只對當前連接可見,在連接關閉時,臨時表會被刪除並釋放所有表空間。
臨時表分爲兩種:一種是內存臨時表
,一種是磁盤臨時表
,什麼區別呢?內存臨時表使用的是 MEMORY 存儲引擎,而臨時表採用的是 MyISAM 存儲引擎。
(8)MySQL 常見索引類型
-
全局索引(FULLTEXT)
:全局索引,目前只有 MyISAM 引擎支持全局索引,它的出現是爲了解決針對文本的模糊查詢效率較低的問題。 -
哈希索引(HASH)
:哈希索引是 MySQL 中用到的唯一 key-value 鍵值對的數據結構,很適合作爲索引。HASH 索引具有一次定位的好處,不需要像樹那樣逐個節點查找,但是這種查找適合應用於查找單個鍵的情況,對於範圍查找,HASH 索引的性能就會很低。 -
B-Tree 索引
:B 就是 Balance 的意思,BTree 是一種平衡樹,它有很多變種,最常見的就是 B+ Tree,它被 MySQL 廣泛使用。 -
R-Tree 索引
:R-Tree 在 MySQL 很少使用,僅支持 geometry 數據類型,支持該類型的存儲引擎只有MyISAM、BDb、InnoDb、NDb、Archive幾種,相對於 B-Tree 來說,R-Tree 的優勢在於範圍查找。
(9)聚簇索引(innodb)和非聚簇索引(myisam)
- 索引:一種提高爲了提高數據查詢效率的數據結構
- 聚簇索引:將數據存儲與索引放到了一起,找到索引也就找到了數據
- 非聚簇索引:(輔助索引)將數據存儲和索引分開的結構,索引結構的葉子節點指向數據對應的行。
myisam通過key_buffer把索引先緩存到內存中,當需要訪問數據時(通過索引訪問數據),在內存中直接搜索索引,然後通過索引找到磁盤相應數據,這也就是爲什麼索引不在key buffer命中時,速度慢的原因
innodb中,在聚簇索引之上創建的索引稱之爲輔助索引,輔助索引訪問數據總是需要二次查找,非聚簇索引都是輔助索引,像複合索引、前綴索引、唯一索引,輔助索引葉子節點存儲的不再是行的物理位置,而是主鍵值
最終目的就是在相同結果集情況下,儘可能減少邏輯IO。
聚簇索引具有唯一性
由於聚簇索引是將數據跟索引結構放到一塊,因此一個表僅有一個聚簇索引
一個誤區:把主鍵自動設爲聚簇索引
聚簇索引默認是主鍵,如果表中沒有定義主鍵,InnoDB 會選擇一個唯一的非空索引代替。如果沒有這樣的索引,InnoDB 會隱式定義一個主鍵來作爲聚簇索引。InnoDB 只聚集在同一個頁面中的記錄。包含相鄰健值的頁面可能相距甚遠。如果你已經設置了主鍵爲聚簇索引,必須先刪除主鍵,然後添加我們想要的聚簇索引,最後恢復設置主鍵即可。
此時其他索引只能被定義爲非聚簇索引。這個是最大的誤區。有的主鍵還是無意義的自動增量字段,那樣的話Clustered index對效率的幫助,完全被浪費了。
剛纔說到了,聚簇索引性能最好而且具有唯一性,所以非常珍貴,必須慎重設置。一般要根據這個表最常用的SQL查詢方式來進行選擇,某個字段作爲聚簇索引,或組合聚簇索引,這個要看實際情況。
記住我們的最終目的就是在相同結果集情況下,儘可能減少邏輯IO。
(9)結合圖再仔細點看
(10)避免索引失效的一些原則
- 複合索引:不要跨列或無序使用(最佳左前綴)(a,b,c),儘量使用全索引匹配 (a,b,c) [用到的字段都用索引]
- 不要在索引上進行任何操作(計算、函數、類型轉換),否則索引失效(單獨索引不影響)
- 複合索引不能使用不等於(!= <>)或is null (is not null),否則自身以及右側所有全部失效。複合索引中如果有>,則自身和右側索引全部失效。
- like儘量以“常量”開頭,不要以’%’開頭,否則索引失效
- 儘量不要使用類型轉換(顯示、隱式),否則索引失效
- 儘量不要使用or,否則索引失效
(11)索引的類型及優先級
id : 編號
select_type :查詢類型
table :表
type :類型
possible_keys :預測用到的索引
key :實際使用的索引
key_len :實際使用索引的長度
ref :表之間的引用
rows :通過索引查詢到的數據量
Extra :額外的信息
Extra:
- using filesort : 性能消耗大;需要“額外”的一次排序(查詢) 。常見於 order by 語句中。 排序:先查詢
- using temporary:性能損耗大 ,用到了臨時表。一般出現在 group by 語句中
- using index :性能提升; 索引覆蓋(覆蓋索引)。原因:不讀取原文件,只從索引文件中獲取數據 (不需要回表查詢)只要使用到的列 全部都在索引中,就是索引覆蓋 using index
- using where (需要回表查詢)
- impossible where : where 子句永遠爲 false
type類型 | 解釋 |
---|---|
null | -- |
system | const的特例,僅返回一條數據的時候。 |
const | 查找主鍵索引,返回的數據至多一條(0或者1條)。 屬於精確查找 |
eq_ref | 查找唯一性索引,返回的數據至多一條。屬於精確查找 |
ref | 查找非唯一性索引,返回匹配某一條件的多條數據。屬於精確查找、數據返回可能是多條 |
range | 查找某個索引的部分索引,一般在where子句中使用 < 、>、in、between等關鍵詞。只檢索給定範圍的行,屬於範圍查找 |
index | 查找所有的索引樹,比ALL要快的多,因爲索引文件要比數據文件小的多。 |
ALL | 不使用任何索引,進行全表掃描,性能最差。 |