一、mysql事務
innodb事務日志包括redo log和undo log。
redo log是重做日志,提供前滾操作,undo log是回滾日志,提供回滾操作。
前滾:
未完全提交的事務,即該事務已經被執行commit命令了,只是現在該事務修改所對應的臟數據塊中只有一部分被寫到磁盤上的數據文件中,還有一部分已經被置為提交標記的臟塊還在內存上,如果此時數據庫實例崩潰了,則當數據庫實例恢復時,就需要用前滾(這個機制)來完成事務的完全提交,即將先前那部分已經被置為提交標記且還在內存上的臟塊寫入到磁盤上的數據文件中。
回滾:
未提交的事務,即該事務未被執行commit命令。但是此時,該事務修改的臟塊中也有可能一部分臟塊寫入到數據文件中了。如果此時數據庫實例崩潰了,則當數據庫實例恢復時,就需要用回滾(這個機制)來將先前那部分已經寫入到數據文件的臟塊從數據文件上撤銷掉。
redo log
redo log包括兩部分:
一是內存中的日志緩沖(redo log buffer),該部分日志是易失性的;
二是磁盤上的重做日志文件(redo log file),該部分日志是持久的。
通常是物理日志,記錄的是數據頁的物理修改,而不是某一行或某幾行修改成怎樣怎樣,它用來恢復提交后的物理數據頁(恢復數據頁,且只能恢復到最后一次提交的位置)。
undo log
一般是邏輯日志,undo用來回滾行記錄到某個版本。,根據每行記錄進行記錄。
undo log和redo log記錄物理日志不一樣,它是邏輯日志。
可以認為當delete一條記錄時,undo log中會記錄一條對應的insert記錄,反之亦然,當update一條記錄時,它記錄一條對應相反的update記錄。
當執行rollback時,就可以從undo log中的邏輯記錄讀取到相應的內容並進行回滾
另外,undo log也會產生redo log,因為undo log也要實現持久性保護。
實質
通過undo log記錄delete和update操作的結果發現:(insert操作無需分析,就是插入行而已)
- delete操作實際上不會直接刪除,而是將delete對象打上delete flag,標記為刪除,最終的刪除操作是purge線程完成的。
- update分為兩種情況:update的列是否是主鍵列。
- 如果不是主鍵列,在undo log中直接反向記錄是如何update的。即update是直接進行的。
- 如果是主鍵列,update分兩部執行:先刪除該行,再插入一行目標行。
恢復
在啟動innodb的時候,不管上次是正常關閉還是異常關閉,總是會進行恢復操作。
因為redo log記錄的是數據頁的物理變化,因此恢復的時候速度比邏輯日志(如二進制日志)要快很多。而且,innodb自身也做了一定程度的優化,讓恢復速度變得更快。
與Redis事務區別
mysql:
-
寫方面: 事務開啟時,事務中的操作,都會先寫入存儲引擎的日志緩沖中
-
提交: 當事務提交之后,在Buffer Pool中映射的數據文件才會慢慢刷新到磁盤。
-
回滾:此時如果數據庫崩潰或者宕機,那么當系統重啟進行恢復時,就可以根據redo log中記錄的日志,把數據庫恢復到崩潰前的一個狀態。未完成的事務,可以繼續提交,也可以選擇回滾,這基於恢復的策略而定。
redis:
-
寫:所有命令都會被序列化
-
提交:在事務提交過程,會按照順序串行化執行隊列中的命令
-
回滾:沒有回滾。事務中任意命令執行失敗,其余的命令仍會被執行
二、Redis事務
Redis事務的概念:
Redis 事務的本質是一組命令的集合。事務支持一次執行多個命令,一個事務中所有命令都會被序列化。在事務執行過程,會按照順序串行化執行隊列中的命令,其他客戶端提交的命令請求不會插入到事務執行命令序列中。
總結說:redis事務就是一次性、順序性、排他性的執行一個隊列中的一系列命令。
Redis事務沒有隔離級別的概念:
批量操作在發送 EXEC 命令前被放入隊列緩存,並不會被實際執行,也就不存在事務內的查詢要看到事務里的更新,事務外查詢不能看到。
Redis不保證原子性:
Redis中,單條命令是原子性執行的,但事務不保證原子性,且沒有回滾。事務中任意命令執行失敗,其余的命令仍會被執行。
Redis事務的三個階段:
- 開始事務
- 命令入隊
- 執行事務
三、MySql鎖
MyISAM和MEMORY采用表級鎖(table-level locking)
BDB采用頁面鎖(page-level locking)或表級鎖,默認為頁面鎖
InnoDB支持行級鎖(row-level locking)和表級鎖,默認為行級鎖
3.1按照對數據操作的鎖粒度來分
1 行級鎖(加在索引上的鎖)
行級鎖分為共享鎖和排他鎖
(1) 描述
行級鎖是mysql中鎖定粒度最細的一種鎖。表示只針對當前操作的行進行加鎖。行級鎖能大大減少數據庫操作的沖突,其加鎖粒度最小,但加鎖的開銷也最大。行級鎖分為共享鎖和排他鎖
(2) 特點
開銷大,加鎖慢,會出現死鎖。發生鎖沖突的概率最低,並發度也最高。
InnoDB有三種行鎖的算法(排他鎖):
1,Record Lock(記錄鎖):單個行記錄上的鎖。這個也是我們日常認為的行鎖。
2,Gap Lock(間隙鎖):間隙鎖,鎖定一個范圍,但不包括記錄本身(只不過它的鎖粒度比記錄鎖的鎖整行更大一些,他是鎖住了某個范圍內的多個行,包括根本不存在的數據)。
GAP鎖的目的,是為了防止同一事務的兩次當前讀,出現幻讀的情況。
該鎖只會在隔離級別是RR或者以上的級別內存在。
間隙鎖的目的是為了讓其他事務無法在間隙中新增數據。
3,Next-Key Lock(臨鍵鎖):它是記錄鎖和間隙鎖的結合,鎖定一個范圍,並且鎖定記錄本身。對於行的查詢,都是采用該方法,主要目的是解決幻讀的問題。next-key鎖是InnoDB默認的鎖
record lock、gap lock、next-key lock,都是加在索引上的。假設有記錄1,3,5,7,
則5上的記錄鎖會鎖住5,
5上的gap lock會鎖住(3,5),
5上的next-key lock會鎖住(3,5]。
2 表級鎖
(1) 描述
表級鎖是mysql中鎖定粒度最大的一種鎖,表示對當前操作的整張表加鎖,它實現簡單,資源消耗較少,被大部分mysql引擎支持。最常使用的MyISAM與InnoDB都支持表級鎖定。表級鎖定分為表共享讀鎖(共享鎖)與表獨占寫鎖(排他鎖)
(2) 特點
開銷小,加鎖快,不會出現死鎖。發生鎖沖突的概率最高,並發度也最低。
- LOCK TABLE my_table_name READ; 用讀鎖鎖表,會阻塞其他事務修改表數據。
- LOCK TABLE my_table_name WRITE; 用寫鎖鎖表,會阻塞其他事務讀和寫。
MyISAM在執行查詢語句(SELECT)前,會自動給涉及的所有表加讀鎖,
在執行更新操作(UPDATE、DELETE、INSERT等)前,會自動給涉及的表加寫鎖,這個過程並不需要用戶干預,
因此,用戶一般不需要直接用LOCK TABLE命令給MyISAM表顯式加鎖。
但是在InnoDB中如果需要表鎖就需要顯式地聲明了
3 頁級鎖
(1) 描述
頁級鎖是 MySQL 中鎖定粒度介於行級鎖和表級鎖中間的一種鎖。表級鎖速度快,但沖突多,行級沖突少,但速度慢。
因此,采取了折中的頁級鎖,一次鎖定相鄰的一組記錄。BDB 支持頁級鎖。
(2) 特點
開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,並發度一般。
3.2按照鎖的共享策略來分
共享鎖和排他鎖在MySQL中具體的實現就是讀鎖和寫鎖:
- 讀鎖(共享鎖):Shared Locks(S鎖),針對同一份數據,多個讀操作可以同時進行而不會互相影響
- 寫鎖(排它鎖):Exclusive Locks(X鎖),當前寫操作沒有完成前,它會阻斷其他寫鎖和讀鎖
- IS鎖:意向共享鎖、Intention Shared Lock。當事務准備在某條記錄上加S鎖時,需要先在表級別加一個IS鎖。
- IX鎖:意向排他鎖、Intention Exclusive Lock。當事務准備在某條記錄上加X鎖時,需要先在表級別加一個IX鎖。
它們的提出僅僅為了在之后加表級別的S鎖和X鎖時可以快速判斷表中的記錄是否被上鎖,
以避免用遍歷的方式來查看表中有沒有上鎖的記錄。
注意:如果一個表中有多個行鎖,他們都會給表加上意向鎖,意向鎖和意向鎖之間是不會沖突的。
3.3從加鎖策略上分
樂觀鎖
樂觀鎖在操作數據時非常樂觀,認為別人不會同時修改數據。
因此樂觀鎖不會上鎖,只是在執行更新的時候判斷一下在此期間別人是否修改了數據:如果別人修改了數據則放棄操作,否則執行操作。
樂觀鎖的實現方式主要有兩種:CAS機制和版本號機制
CAS操作邏輯如下:
如果內存位置V的值等於預期的A值,則將該位置更新為新值B,否則不進行任何操作。
許多CAS的操作是自旋的:如果操作不成功,會一直重試,直到操作成功為止。
版本號機制:
的基本思路是在數據中增加一個字段version,表示該數據的版本號,每當數據被修改,版本號加1。
- 當某個線程查詢數據時,將該數據的版本號一起查出來;
- 當該線程更新數據時,判斷當前版本號與之前讀取的版本號是否一致,如果一致才進行操作
悲觀鎖
悲觀鎖在操作數據時比較悲觀,認為別人會同時修改數據。
因此操作數據時直接把數據鎖住,直到操作完成后才會釋放鎖;上鎖期間其他人不能修改數據。
3.4自增鎖
自增鎖(AUTO-INC鎖)
自增鎖是一種特殊的表級鎖,主要用於事務中插入自增字段,也就是我們最常用的自增主鍵id。
通過innodb_autoinc_lock_mode參數可以設置自增主鍵的生成策略。防止並發插入數據的時候自增id出現異常。
當一張表的某個字段是自增列時,innodb會在該索引的末位加一個排它鎖。
為了訪問這個自增的數值,需要加一個表級鎖,不過這個表級鎖的持續時間只有當前sql,而不是整個事務,即當前sql執行完,該表級鎖就釋放了。其他session無法在這個表級鎖持有時插入任何記錄。
四、MySQL InnoDB存儲引擎
InnoDB優勢
1)支持事務
InnoDB 最重要的一點就是支持事務,可以說這是 InnoDB 成為 MySQL 中最流行的存儲引擎的一個非常重要的原因
InnoDB 還實現了 SQL92 標准所定義的 4 個隔離級別
2)災難恢復性好
commit、rollback、crash-recovery 來保障數據的安全
3)使用行級鎖
InnoDB 的行鎖機制是通過索引來完成的,但畢竟在數據庫中 99%的 SQL 語句都要使用索引來檢索數據。行鎖定機制也為 InnoDB 在承受高並發壓力的環境下增強了不小的競爭力。
4)實現了緩沖處理
InnoDB 提供了專門的緩存池,實現了緩沖管理,不僅能緩沖索引也能緩沖數據,常用的數據可以直接從內存中處理,比從磁盤獲取數據處理速度要快。
當一條 SQL 執行的時候,如果是讀操作,要查找的數據所在的數據頁在內存中時,則將結果返回。否則會把對應的數據頁加載到內存中,然后再返回結果。
同樣對於寫操作來說。如果要修改的行所在的數據頁在內存中,則修改后返回對應的結果(當然還有后續操作)。如果不在的話,則會從磁盤里將該行所對應的數據頁讀到內存中再進行修改。
1.緩沖池的預讀機制
InnoDB使用兩種預讀算法來提高I/O性能:線性預讀(linear read-ahead)和隨機預讀
會產生兩個問題
緩沖池污染問題
還有一種情況是當執行一條 SQL 語句時,如果掃描了大量數據或是進行了全表掃描,此時緩沖池中就會加載大量的數據頁,從而將緩沖池中已存在的所有頁替換出去,這種情況同樣是不合理的。這就是緩沖池污染,並且還會導致 MySQL 性能急劇下降。
預讀失效問題
被預先加載進緩沖池的頁,並沒有被訪問到
2.緩沖刷新策略
通常來說,緩沖池是通過LRU(Latest Recent Used,最近最少使用)
5)文件大小不受限制
InnoDB 的表和索引在一個邏輯表空間中,表空間可以包含數個文件(或原始磁盤分區)。
這與 MyISAM 表不同,比如在 MyISAM 表中每個表被保存在分離的文件中。
InnoDB 表可以是任何尺寸,即使在文件尺寸被限制為 2GB 的操作系統上。
6)支持外鍵
InnoDB 支持外鍵約束,檢查外鍵、插入、更新和刪除,以確保數據的完整性。
在存儲表中數據時每張表的存儲都按主鍵順序存放,如果沒有顯式地在定義表時指定主鍵,InnoDB 會為每一行生成一個 6 字節的 ROWID ,並以此作為主鍵。
物理存儲
1. 數據文件(表數據和索引數據)
數據文件用來存放數據表中的數據和所有的索引數據,包括主鍵和其他普通索引。
InnoDB 存儲的數據采用表空間(Tablepace)進行存放設計。表空間是用來存放 MySQL 系統相關信息的一個特殊共享表空間。
InnoDB 的表空間分為以下兩種形式:
- 共享表空間,表數據和索引都存放在同一個表空間。默認的表空間文件就是上面所提到的 MySQL 初始化路徑下的 ibdata1 文件。
- 獨立表空間,每個表的數據和索引被存放在一個單獨的 .ibd 文件中。
InnoDB 的表空間分為以下兩種形式:
- 共享表空間,表數據和索引都存放在同一個表空間。默認的表空間文件就是上面所提到的 MySQL 初始化路徑下的 ibdata1 文件。
- 獨立表空間,每個表的數據和索引被存放在一個單獨的 .ibd 文件中。
2. 日志文件
默認情況下,InnoDB 存儲引擎的數據目錄下會有兩個名為 ib_logfile0 和 ib_logfile1 的文件。在 MySQL 官方手冊中將其稱為 InnoDB 存儲引擎的重做日志文件(redo log file)。
每個 InnoDB 存儲引擎至少有 1 個重做日志文件組(group),
每個文件組下至少有 2 個重做日志文件,如默認的 ib_logfile0 和 ib_logfile1。
五、MySql相關小知識
1.自增主鍵用完了該怎么辦
旦自增id達到最大值,此時數據繼續插入是會報一個主鍵沖突異常如下所示
//Duplicate entry '4294967295' for key 'PRIMARY'
解決方法:將Int類型改為BigInt類型
1.1線上怎么修改列的數據類型的
方式一:使用mysql5.6+提供的在線修改功能
對於修改數據類型這種操作,是不支持並發的DML操作!也就是說,如果你直接使用ALTER這樣的語句在線修改表數據結構,會導致這張表無法進行更新類操作(DELETE、UPDATE、DELETE)。 因此,直接ALTER是不行滴!
方式二:借助第三方工具
1、pt-online-schema-change,簡稱pt-osc - 2、GitHub正式宣布以開源的方式發布的工具,名為gh-ost
如果你的表里有觸發器和外鍵,這兩個工具是不行
方式三:改從庫表結構,然后主從切換
mysql架構一般是讀寫分離架構,從機是用來讀的。我們直接在從庫上進行表結構修改,不會阻塞從庫的讀操作。改完之后,進行主從切換即可。
可能會有數據丟失的情況
但是:
一般達不到最大值,我們就分庫分表了,所以不曾遇見過!"
2.char和varchar的區別
-
char類型的長度是固定的,varchar的長度是可變的。
這就表示,存儲字符串'abc',使用char(10),表示存儲的字符將占10個字節,如果不足10字節,將使用空格占位,所以檢索CHAR值時需刪除尾隨空格
使用varchar2(10),,則表示只占3個字節,10是最大值,當存儲的字符小於10時,按照實際的長儲。
-
2.char類型的效率比varchar的效率稍高
3.set字段類型
SET是一個字符串對象,可以有零或多個值,其值來自表創建時規定的允許的一列值。
指定包括多個SET成員的SET列值時各成員之間用逗號(‘,’)間隔開。這樣SET成員值本身不能包含逗號。
SET最多可以有64個不同的成員。
當創建表時,SET成員值的尾部空格將自動被刪除。
4.BLOB 和 TEXT 有什么區別?
TEXT與BLOB的主要差別就是BLOB保存二進制數據,TEXT保存字符數據。。
主要差別
TEXT與BLOB的主要差別就是BLOB保存二進制數據,TEXT保存字符數據。
目前幾乎所有博客內容里的圖片都不是以二進制存儲在數據庫的,而是把圖片上傳到服務器然后正文里使用
標簽引用,這樣的博客就可以使用TEXT類型。而BLOB就可以把圖片換算成二進制保存到數據庫中。
5.MySQL數據庫預計運維三年,怎么優化?
1、設計良好的數據庫結構,允許部分數據冗余,盡量避免 join 查詢,提高效率。
2、選擇合適的表字段數據類型和存儲引擎,適當的添加索引。
3、MySQL 庫主從讀寫分離。
4、找規律分表,減少單表中的數據量提高查詢速度。
5、添加緩存機制,比如 memcached,apc 等。
6、不經常改動的頁面,生成靜態頁面。
7、書寫高效率的 SQL。比如 SELECT ***** FROM TABEL 改為 SELECT field_1, field_2, field_3 FROM TABLE
6.什么是存儲過程?用什么來調用?
存儲過程是一個預編譯的 SQL 語句,優點是允許模塊化的設計,就是說只需創建一次,以后在該程序中就可以調用多次。
如果某次操作需要執行多次 SQL, 使用存儲過程比單純 SQL 語句執行要快。可以用一個命令對象來調用存儲過程
7.什么是觸發器,可以用來做什么
觸發器是與 MySQL 數據表有關的數據庫對象,在滿足定義條件時觸發,並執行觸發器中定義的語句集合
觸發器的這種特性可以協助應用在數據庫端確保數據的完整性。
六、MySQL索引底層實現原理
索引是數據結構。
數據庫系統的設計者會從查詢算法的角度進行優化。最基本的查詢算法當然是順序查找(linear search),這種復雜度為O(n)的算法在數據量很大時顯然是糟糕的。
計算機科學的發展提供了很多更優秀的查找算法,例如二分查找(binary search)、二叉樹查找(binary tree search)等
但是數據本身的組織結構不可能完全滿足各種數據結構(例如,理論上不可能同時將兩列都按順序進行組織),所以,數據庫系統還維護着滿足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就可以在這些數據結構上實現高級查找算法。這種數據結構,就是索引。
6.1B樹
B樹事實上是一種平衡的多叉查找樹,也就是說最多可以開m個叉(m>=2)
二、五階B樹

B樹的查詢過程和二叉排序樹比較類似,從根節點依次比較每個結點,因為每個節點中的關鍵字和左右子樹都是有序的,所以只要比較節點中的關鍵字,或者沿着指針就能很快地找到指定的關鍵字,如果查找失敗,則會返回葉子節點,即空指針。
6.2Plus版 — B+樹
作為B樹的加強版,B+樹與B樹的差異在於
- 所有的關鍵字全部存儲在葉子節點上,且葉子節點本身根據關鍵字自小而大順序連接。
- 非葉子節點可以看成索引部分,節點中僅含有其子樹(根節點)中的最大(或最小)關鍵字。
- 有n棵子樹的節點含有n個關鍵字(也有認為是n-1個關鍵字)。
查找:
B+樹的查找過程,與B樹類似,只不過查找時,如果在非葉子節點上的關鍵字等於給定值,並不終止,而是繼續沿着指針直到葉子節點位置。因此在B+樹,不管查找成功與否,每次查找都是走了一條從根到葉子節點的路徑。
特性
- 所有關鍵字都存儲在葉子節上,且鏈表中的關鍵字恰好是有序的。
- 不可能非葉子節點命中返回。
- 非葉子節點相當於葉子節點的索引,葉子節點相當於是存儲(關鍵字)數據的數據層。
- 更適合文件索引系統。
6.3為什么使用B樹(B+樹)
一般來說,索引本身也很大,不可能全部存儲在內存中,因此索引往往以索引文件的形式存儲在磁盤上。
這樣的話,索引查找過程中就要產生磁盤I/O消耗,相對於內存存取,I/O存取的消耗要高幾個數量級,所以評價一個數據結構作為索引的優劣最重要的指標就是在查找過程中磁盤I/O操作次數的漸進復雜度。
換句話說,索引的結構組織要盡量減少查找過程中磁盤I/O的存取次數。下面先介紹內存和磁盤存取原理,然后再結合這些原理分析B-/+Tree作為索引的效率
主存存取原理
當系統需要讀取主存時,則將地址信號放到地址總線上傳給主存,主存讀到地址信號后,解析信號並定位到指定存儲單元,然后將此存儲單元數據放到數據總線上,供其它部件讀取。
主存存取的時間僅與存取次數呈線性關系,因為不存在機械操作
磁盤存取原理
當需要從磁盤讀取數據時,系統會將數據邏輯地址傳給磁盤,
磁盤的控制電路按照尋址邏輯將邏輯地址翻譯成物理地址,即確定要讀的數據在哪個磁道,哪個扇區。
為了讀取這個扇區的數據,需要將磁頭放到這個扇區上方,為了實現這一點,磁頭需要移動對准相應磁道,這個過程叫做尋道,所耗費時間叫做尋道時間,然后磁盤旋轉將目標扇區旋轉到磁頭下,這個過程耗費的時間叫做旋轉時間。
局部性原理與磁盤預讀
局部性原理:當一個數據被用到時,其附近的數據也通常會馬上被使用。從這個位置開始,順序向后讀取一定長度的數據放入內存
磁盤預讀:預讀的長度一般為頁(page)的整倍數。
頁是計算機管理存儲器的邏輯塊,硬件及操作系統往往將主存和磁盤存儲區分割為連續的大小相等的塊,每個存儲塊稱為一頁(在許多 操作系統中,頁得大小通常為4k)
主存和磁盤以頁為單位交換數據。當程序要讀取的數據不在主存中時,會觸發一個缺頁異常,此時系統會向磁盤發出讀盤信號,磁盤會 找到數據的起始位置並向后連續讀取一頁或幾頁載入內存中,然后異常返回,程序繼續運行。
此時如果緩存空間滿了,就會觸發緩存過期策略
緩存過期策略:
FIFO:First In First Out,先進先出
LRU:Least Recently Used,最近最少使用
LFU:Least Frequently Used,最不經常使用
性能分析總結
數據庫系統的設計者巧妙利用了磁盤預讀原理,將一個節點的大小設為等於一個頁,這樣每個節點只需要一次I/O就可以完全載入。
B-Tree中一次檢索最多需要h-1次I/O(根節點常駐內存),漸進復雜度為O(h)=O(logdN)O(h)=O(logdN)。
一般實際應用中,出度d是非常大的數字,通常超過100,因此h非常小(通常不超過3)。
(h表示樹的高度 & 出度d表示的是樹的度,即樹中各個節點的度的最大值)
而紅黑樹這種結構,h明顯要深的多。由於邏輯上很近的節點(父子)物理上可能很遠,無法利用局部性,所以紅黑樹效率明顯比B-Tree差很多。
綜上所述,用B-Tree作為索引結構效率是非常高的。
此外:因為數據都是存儲在葉子節點上的,所以非葉子節點上沒有數據域,因此可以擁有更大的出度,從而擁有更好的性能。
6.4MySQL索引實現
MYISAM索引實現

可以看出MyISAM的索引文件僅僅保存數據記錄的地址。
在MyISAM中,主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求key是唯一的,而輔助索引的key可以重復。
因此,MyISAM中索引檢索的算法為首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,則取出其data域的值,然后以data域的值為地址,讀取相應數據記錄。
MyISAM的索引方式也叫做“非聚集”的,之所以這么稱呼是為了與InnoDB的聚集索引區分。
InnoDB索引實現


在InnoDB中,表數據文件本身就是按B+Tree組織的一個索引結構,這棵樹的葉節點data域保存了完整的數據記錄。
這個索引的key是數據表的主鍵,因此InnoDB表數據文件本身就是主索引。
與myisam不同點
-
葉節點包含了完整的數據記錄。這種索引叫做聚集索引。因為InnoDB的數據文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有)
-
第二個與MyISAM索引的不同是InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。換句話說,InnoDB的所有輔助索引都引用主鍵作為data域。
聚集索引這種實現方式使得按主鍵的搜索十分高效,但是輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵,然后用主鍵到主索引中檢索獲得記錄。
使用聚簇索引的優勢
-
輔助索引的葉子節點,存儲主鍵值,而不是數據的存放地址。好處是當行數據放生變化時,索引樹的節點也需要分裂變化;
如果存儲完整記錄,則需要對輔助索引維護,只存主鍵值,那么只需要維護聚簇索引樹就可以了。
-
因為輔助索引存放的是主鍵值,減少了輔助索引占用的存儲空間大小。
-
聚簇索引的數據的物理存放順序與索引順序是一致的,即:只要索引是相鄰的,那么對應的數據一定也是相鄰地存放在磁盤上的
非聚簇索引,那么他的數據的物理地址必然是凌亂的,為了拿到數據,需要不停的尋道不停的旋轉。
而聚簇索引則只需一次I/O就可以獲得一頁的數據。(強烈的對比)
6.5總結
1.索引是利用空間換取時間,將數據的引用按照合適的數據結構存儲,就是索引
2.索引使用b+樹,因為b+樹很適合文件系統查找
3.了解索引的實現,在創建索引的時候,可以提升表的效率
七、Mysql優化
Mysql的優化,大體可以分為三部分:索引的優化,sql語句的優化,表的優化
1.索引優化
一般的應用系統,讀寫比例在10:1左右,在生產環境中,我們遇到最多的也是最容易出現問題的,還是一些復雜的查詢操作,
因此對查詢語句的優化是重中之重,加速查詢最好的方法就是索引。
索引類型
普通索引:是最基本的索引,它沒有任何限制。
唯一索引:索引列的值必須唯一,但允許有空值。如果是組合索引,則列值的組合必須唯一。
組合索引:指多個字段上創建的索引,只有在查詢條件中使用了創建索引時的第一個字段,索引才會被使用。
主鍵索引:是一種特殊的唯一索引,一個表只能有一個主鍵,不允許有空值。一般是在建表的時候同時創建主鍵索引
全文索引:主要用來查找文本中的關鍵字,而不是直接與索引中的值相比較。它更像是一個搜索引擎
索引優化
- 只要列中含有NULL值,就最好不要在此例設置索引,復合索引如果有NULL值,此列在使用時也不會使用索引
- 盡量使用短索引,如果可以,應該制定一個前綴長度
- 對於經常在where子句使用的列,最好設置索引,這樣會加快查找速度
- 對於有多個列where或者order by子句的,應該建立復合索引
- 對於like語句,以%或者‘-’開頭的不會使用索引,以%結尾會使用索引
- 盡量不要在列上進行運算(函數操作和表達式操作)
- 盡量不要使用not in和<>操作
2.sql慢查詢優化
操作
-
如何捕獲低效sql
slow_query_log=ON/OFF;
-
執行時間超過此數值時,就會被記錄到日志中
long_query_time=n;
-
設置日志名
slow_query_log_file
步驟
- 先運行看看是否真的很慢,注意設置SQL_NO_CACHE(在查詢時,不使用緩存)
- where鎖定最小返回記錄表(單表每個字段分別查詢,看哪個字段的區分度最高)
- explain查看執行計划
- 按照查詢,加入索引,參照建索引的幾大原則
- 觀察結果
優化的原則
- 查詢時,能不要*就不用,盡量寫全字段名
- 大部分情況連接效率遠大於子查詢
- 多使用explain和profile分析查詢語句
- 查看慢查詢日志,找出執行時間長的sql語句優化
- 多表連接時,盡量小表驅動大表,即小表 join 大表
- 在千萬級分頁時使用limit
- 對於經常使用的查詢,可以開啟緩存
開啟緩存
1、修改配置文件my.ini
windows下是my.ini,linux下是my.cnf;
在配置文件的最后追加上:
query_cache_type = 1
query_cache_size = 600000
需要重啟mysql生效;
2.命令方式
set global query_cache_type = 1;
set global query_cache_size = 600000;
3.數據庫表優化
- 表的字段盡可能用NOT NULL
- 字段長度固定的表查詢會更快
- 把數據庫的大表按時間或一些標志分成小表
- 將表拆分
數據表拆分
主要就是垂直拆分和水平拆分。
水平切分:將記錄散列到不同的表中,各表的結構完全相同,每次從分表中查詢, 提高效率。
垂直切分:將表中大字段單獨拆分到另外一張表, 形成一對一的關系(谷粒學院中的course表就拆分為了course和course_discription)
