<a href="#_Toc431924777">14 InnoDB存儲引擎... 1</a>
<a href="#_Toc431924778">14.1 InnoDB說明... 5</a>
<a href="#_Toc431924779">14.1.1 InnoDB作為預設存儲引擎... 5</a>
<a href="#_Toc431924780">14.1.1.1 存儲引擎的趨勢... 5</a>
<a href="#_Toc431924781">14.1.1.2 InnoDB變成預設存儲引擎之後... 5</a>
<a href="#_Toc431924782">14.1.1.3 InnoDB表好處... 6</a>
<a href="#_Toc431924783">14.1.1.4 InnoDB表最佳實踐... 6</a>
<a href="#_Toc431924784">14.1.1.5 InnoDB表提升... 6</a>
<a href="#_Toc431924785">14.1.1.6 InnoDB作為預設存儲引擎測試... 6</a>
<a href="#_Toc431924786">14.1.1.7 驗證InnoDB是預設存儲引擎... 7</a>
<a href="#_Toc431924787">14.1.2 檢查InnoDB可用... 7</a>
<a href="#_Toc431924788">14.1.3 關閉InnoDB. 7</a>
<a href="#_Toc431924789">14.2 InnoDB概念和體系結構... 8</a>
<a href="#_Toc431924790">14.2.1 Mysql和ACID模型... 8</a>
<a href="#_Toc431924791">14.2.2 InnoDB事務模式和鎖... 9</a>
<a href="#_Toc431924792">14.2.3 InnoDB鎖定模式... 9</a>
<a href="#_Toc431924793">14.2.3.1 意向鎖... 9</a>
<a href="#_Toc431924794">14.2.3.2 死鎖例子... 10</a>
<a href="#_Toc431924795">14.2.4 一緻性無鎖讀... 10</a>
<a href="#_Toc431924796">14.2.5 鎖讀... 11</a>
<a href="#_Toc431924797">14.2.6 InnoDB Record,Gap,Next-key鎖... 11</a>
<a href="#_Toc431924798">14.2.6.1 Record Lock. 11</a>
<a href="#_Toc431924799">14.2.6.2 Next-Key Lock. 11</a>
<a href="#_Toc431924800">14.2.6.3 Gap Lock. 11</a>
<a href="#_Toc431924801">14.2.7 使用Next-key鎖定避免幻影... 11</a>
<a href="#_Toc431924802">14.2.8 不同語句的鎖定設定... 12</a>
<a href="#_Toc431924803">14.2.9 事務送出和復原的影響... 13</a>
<a href="#_Toc431924804">14.2.10 死鎖發現和復原... 13</a>
<a href="#_Toc431924805">14.2.11 如何處理死鎖... 13</a>
<a href="#_Toc431924806">14.2.12 InnoDB多版本... 14</a>
<a href="#_Toc431924807">14.2.12.1 多版本内部細節... 14</a>
<a href="#_Toc431924808">14.2.12.2 Rollback Segment管理指導... 14</a>
<a href="#_Toc431924809">14.2.13 InnoDB表和索引結構... 14</a>
<a href="#_Toc431924810">14.2.13.1 .frm檔案在innodb表的角色... 14</a>
<a href="#_Toc431924811">14.2.13.2 聚集和secondary索引... 15</a>
<a href="#_Toc431924812">14.2.13.3 FULLTEXT索引... 15</a>
<a href="#_Toc431924813">14.2.13.4 索引的實體結構... 15</a>
<a href="#_Toc431924814">14.2.13.5 Insert Buffering. 15</a>
<a href="#_Toc431924815">14.2.13.6 自适應hash索引... 16</a>
<a href="#_Toc431924816">14.2.13.7 實體行結構... 16</a>
<a href="#_Toc431924817">14.3 InnoDB配置... 16</a>
<a href="#_Toc431924818">14.3.1 配置InnoDB為隻讀... 17</a>
<a href="#_Toc431924819">14.3.1.1 如何啟動... 17</a>
<a href="#_Toc431924820">14.3.1.2 使用場景... 17</a>
<a href="#_Toc431924821">14.3.1.3 如何工作... 17</a>
<a href="#_Toc431924822">14.4 InnoDB管理... 18</a>
<a href="#_Toc431924823">14.5 InnoDB表空間管理... 18</a>
<a href="#_Toc431924824">14.5.2 InnoDB File-Per-Table模式... 18</a>
<a href="#_Toc431924825">14.5.3 啟動禁用File-Per-Table模式... 19</a>
<a href="#_Toc431924826">14.5.4 指定TableSpace的路徑... 19</a>
<a href="#_Toc431924827">14.5.5 把表空間複制到另外一個服務上... 20</a>
<a href="#_Toc431924828">14.5.6 把undo log移出System表空間... 21</a>
<a href="#_Toc431924829">14.5.7 修改InnoDB日志檔案,增長InnoDB表空間... 21</a>
<a href="#_Toc431924830">14.5.8 使用原生磁盤分區作為系統表空間... 22</a>
<a href="#_Toc431924831">14.6 InnoDB表管理... 23</a>
<a href="#_Toc431924832">14.6.1 建立InnoDB表... 23</a>
<a href="#_Toc431924833">14.6.2 把InnoDB表移動到另一個機器... 24</a>
<a href="#_Toc431924834">14.6.2.1 跨平台複制移動使用小寫... 24</a>
<a href="#_Toc431924835">14.6.2.2 傳輸表空間... 24</a>
<a href="#_Toc431924836">14.6.2.3 MySQL企業備份... 24</a>
<a href="#_Toc431924837">14.6.2.4 複制資料檔案... 24</a>
<a href="#_Toc431924838">14.6.2.5 ibd檔案可移植性... 24</a>
<a href="#_Toc431924839">14.6.3 使用事務批量DML操作... 25</a>
<a href="#_Toc431924840">14.6.4 把MyISAM轉化為InnoDB. 25</a>
<a href="#_Toc431924841">14.6.4.1 減少MyISAM記憶體使用,增加InnoDB記憶體使用... 25</a>
<a href="#_Toc431924842">14.6.4.2 檢視太長或者太短的事務... 25</a>
<a href="#_Toc431924843">14.6.4.3 不要太擔心死鎖... 26</a>
<a href="#_Toc431924844">14.6.4.4 計劃存儲分布... 26</a>
<a href="#_Toc431924845">14.6.4.5 轉化一個現有的表... 26</a>
<a href="#_Toc431924846">14.6.4.6 克隆表結構... 26</a>
<a href="#_Toc431924847">14.6.4.7 轉化已存在資料... 26</a>
<a href="#_Toc431924848">14.6.4.8 存儲需求... 27</a>
<a href="#_Toc431924849">14.6.4.9 仔細選擇Primary Key. 27</a>
<a href="#_Toc431924850">14.6.4.10 應用程式性能考慮... 27</a>
<a href="#_Toc431924851">14.6.4.11 InnoDB表和檔案的關聯... 27</a>
<a href="#_Toc431924852">14.6.5 InnoDB自增處理... 27</a>
<a href="#_Toc431924853">14.6.5.1 傳統InnoDB自增長鎖... 27</a>
<a href="#_Toc431924854">14.6.5.2 配置InnoDB自增鎖... 28</a>
<a href="#_Toc431924855">14.6.6 InnoDB和外鍵限制... 30</a>
<a href="#_Toc431924856">14.6.7 InnoDB表的限制... 30</a>
<a href="#_Toc431924857">14.6.7.1 最大和最小... 30</a>
<a href="#_Toc431924858">14.6.7.2 索引類型... 31</a>
<a href="#_Toc431924859">14.6.7.3 InnoDB表的限制... 31</a>
<a href="#_Toc431924860">14.6.7.4 鎖定和事務... 32</a>
<a href="#_Toc431924861">14.7 InnoDB壓縮表... 32</a>
<a href="#_Toc431924862">14.7.1 表壓縮概述... 32</a>
<a href="#_Toc431924863">14.7.2 啟動壓縮表... 32</a>
<a href="#_Toc431924864">14.7.3 InnoDB壓縮表調優... 33</a>
<a href="#_Toc431924865">14.3.7.1 什麼時候使用壓縮... 33</a>
<a href="#_Toc431924866">14.3.7.2 資料特性和壓縮... 34</a>
<a href="#_Toc431924867">14.3.7.3 資料庫壓縮VS應用程式壓縮... 34</a>
<a href="#_Toc431924868">14.3.7.4 工作負荷特點和壓縮... 34</a>
<a href="#_Toc431924869">14.3.7.5 配置特點和壓縮... 34</a>
<a href="#_Toc431924870">14.3.7.6 選擇壓縮page大小... 35</a>
<a href="#_Toc431924871">14.7.4 監視壓縮... 35</a>
<a href="#_Toc431924872">14.7.5 InnoDB如何壓縮... 35</a>
<a href="#_Toc431924873">14.7.5.1 壓縮算法... 35</a>
<a href="#_Toc431924874">14.7.5.2 InnoDB存儲引擎和壓縮... 35</a>
<a href="#_Toc431924875">14.7.5.3 B樹頁壓縮... 36</a>
<a href="#_Toc431924876">14.7.5.4 壓縮BLOB,VARCHAR,TEXT列... 36</a>
<a href="#_Toc431924877">14.7.5.5 壓縮和innodb buffer pool36</a>
<a href="#_Toc431924878">14.7.5.6 壓縮和InnoDB Redo Log檔案... 37</a>
<a href="#_Toc431924879">14.7.6 OLTP負荷的壓縮... 37</a>
<a href="#_Toc431924880">14.7.7 壓縮文法警告和錯誤... 37</a>
<a href="#_Toc431924881">14.8 InnoDB檔案格式管理... 39</a>
<a href="#_Toc431924882">14.8.1 啟動檔案格式... 39</a>
<a href="#_Toc431924883">14.8.2 驗證檔案相容模式... 39</a>
<a href="#_Toc431924884">14.8.2.1 InnoDB打開時的相容性檢查... 40</a>
<a href="#_Toc431924885">14.8.2.2 表打開時的相容性檢查... 40</a>
<a href="#_Toc431924886">14.8.3 識别使用的檔案格式... 41</a>
<a href="#_Toc431924887">14.8.4 檔案格式降級... 41</a>
<a href="#_Toc431924888">14.9 InnoDB 行存儲和行格式... 41</a>
<a href="#_Toc431924889">14.9.1 InnoDB行存儲概述... 41</a>
<a href="#_Toc431924890">14.9.2 位表指定行格式... 42</a>
<a href="#_Toc431924891">14.9.3 DYNAMIC和COMPRESSED行格式... 42</a>
<a href="#_Toc431924892">14.9.4 Compact和REDUNDANT行格式... 42</a>
<a href="#_Toc431924893">14.10 InnoDB磁盤I/O和檔案空間管理... 42</a>
<a href="#_Toc431924894">14.10.1 InnoDB磁盤I/O.. 42</a>
<a href="#_Toc431924895">14.10.2 檔案空間管理... 43</a>
<a href="#_Toc431924896">14.10.3 InnoDB 檢查點... 43</a>
<a href="#_Toc431924897">14.10.4 表整理... 43</a>
<a href="#_Toc431924898">14.10.5 使用TRUNCATE TABLE清理表空間... 44</a>
<a href="#_Toc431924899">14.11 InnoDB和Online DDL. 44</a>
<a href="#_Toc431924900">14.11.1 Online DDL概述... 44</a>
<a href="#_Toc431924901">14.11.2 Online DDL的性能和并發考慮... 45</a>
<a href="#_Toc431924902">14.11.3 Online DDL的SQL文法... 46</a>
<a href="#_Toc431924903">14.11.4 組合和獨立DDL語句... 46</a>
<a href="#_Toc431924904">14.11.5 Online DDL的例子... 47</a>
<a href="#_Toc431924905">14.11.6 Online DDL的細節... 47</a>
<a href="#_Toc431924906">14.11.7 Online DDl Crash如何恢複... 48</a>
<a href="#_Toc431924907">14.11.8 分區表上的Online DDL. 48</a>
<a href="#_Toc431924908">14.11.9 Online DDL限制... 48</a>
<a href="#_Toc431924909">14.12 innodb啟動選項和系統變量... 49</a>
<a href="#_Toc431924910">14.13 InnoDB性能... 49</a>
<a href="#_Toc431924911">14.13.1 InnoDB buffer pool配置... 49</a>
<a href="#_Toc431924912">14.13.1.1 配置InnoDB Buffer Pool預讀(Read-Ahead)49</a>
<a href="#_Toc431924913">14.13.1.2 配置InnoDB重新整理比率... 49</a>
<a href="#_Toc431924914">14.13.1.3 Buffer Pool處理scan. 50</a>
<a href="#_Toc431924915">14.13.1.4 使用多buffer pool執行個體... 51</a>
<a href="#_Toc431924916">14.13.1.5 快速重新開機後加載buffer pool51</a>
<a href="#_Toc431924917">14.13.1.6 調整InnoDB buffer pool重新整理... 52</a>
<a href="#_Toc431924918">14.13.2 InnoDB信号量和Read/Write鎖實作... 52</a>
<a href="#_Toc431924919">14.13.3 配置InnoDB的記憶體配置設定... 53</a>
<a href="#_Toc431924920">14.13.4 配置innodb Change Buffer53</a>
<a href="#_Toc431924921">14.13.5 配置InnoDB的線程并發... 54</a>
<a href="#_Toc431924922">14.13.6 配置innodb I/O背景線程數量... 54</a>
<a href="#_Toc431924923">14.13.7 分組送出... 54</a>
<a href="#_Toc431924924">14.13.8 配置InnoDB主線程I/O率... 55</a>
<a href="#_Toc431924925">14.13.9 在InnoDB自旋循環中使用PAUSE指令... 55</a>
<a href="#_Toc431924926">14.13.10 設定自旋鎖輪詢... 55</a>
<a href="#_Toc431924927">14.13.11 InnoDB使用MySQL性能架構整合... 55</a>
<a href="#_Toc431924928">14.13.12 使用多RollBack Segment獲得更好的擴充性... 56</a>
<a href="#_Toc431924929">14.13.13 配置InnoDB清理排程... 56</a>
<a href="#_Toc431924930">14.13.14 優化InnoDB隻讀事務... 56</a>
<a href="#_Toc431924931">14.13.15 使用CRC32 Checksum算法,快速checksum.. 56</a>
<a href="#_Toc431924932">14.13.16 undo log儲存在獨立包空間... 57</a>
<a href="#_Toc431924933">14.13.17 優化統計資訊... 57</a>
<a href="#_Toc431924934">14.13.17.1 配置持久優化統計資訊參數... 57</a>
<a href="#_Toc431924935">14.13.17.2 配置非持久性統計資訊值... 58</a>
<a href="#_Toc431924936">14.13.18 評估ANALYZE TABLE複雜性... 59</a>
<a href="#_Toc431924937">14.14 InnoDB INFORMATION_SCHEMA表... 59</a>
<a href="#_Toc431924938">14.15 InnoDB螢幕... 59</a>
<a href="#_Toc431924939">14.15.1 InnoDB螢幕類型... 59</a>
<a href="#_Toc431924940">14.15.2 啟動innodb螢幕... 60</a>
<a href="#_Toc431924941">14.15.3 InnoDB标準監控輸出和鎖監控輸出... 61</a>
<a href="#_Toc431924942">14.15.4 InnoDB表空間螢幕輸出... 62</a>
<a href="#_Toc431924943">14.15.5 表螢幕... 63</a>
<a href="#_Toc431924944">14.16 InnoDB備份和恢複... 63</a>
<a href="#_Toc431924945">14.16.1 innodb恢複程序... 63</a>
<a href="#_Toc431924946">14.17 InnoDB和MySQL複制... 63</a>
<a href="#_Toc431924947">14.18 InnoDB內建memcached.. 64</a>
<a href="#_Toc431924948">14.19 InnoDB Troubleshooting. 64</a>
<a href="#_Toc431924949">14.19.1 troubleshooting InnoDB I/O問題... 64</a>
<a href="#_Toc431924950">14.19.2 啟動損壞的資料庫... 65</a>
<a href="#_Toc431924951">14.19.3 排查InnoDB資料字典操作... 65</a>
<a href="#_Toc431924952">14.19.4 InnoDB錯誤處理... 67</a>
<a href="#_Toc431924953">14.19.5 InnoDB錯誤代碼</a>
<a href="#_Toc431924954">14.19.6 系統錯誤代碼</a>
Innodb是通用的存儲引擎,平衡高可用和高性能。從Mysql 5.5開始作為Mysql的預設存儲引擎。
InnoDB重要特點
InnoDB重點:
1.DML操作遵循ACID,支援事務送出,復原和災難恢複來保護資料。
2.支援行鎖,oracle類型的讀一緻性。增加多使用者并發。
3.InnoDB儲存在磁盤中,通過primary key來優化查詢。
4.為了維護資料完整性,InnoDB也支援外鍵限制。
5.InnoDB可以和mysql的其他存儲引擎混合。
6.InnoDB設計,當處理大資料時,最大化性能。
InnoDB存儲引擎特性:
InnoDB自己維護了buffer pool來緩存資料和索引。預設啟動innodb_file_per_table,這樣InnoDB表的索引和資料都被存放在獨立的一個檔案中。如果disable,被儲存在系統表空間中。
在MySQL 5.6之後版本:
1.InnoDB支援全文索引。
2.InnoDB在執行隻讀,或者讀多寫少比較出色。
3.在隻讀媒體上可以使用InnoDB表。
從MySQL 5.5.5之後預設存儲引擎變成了InnoDB,可以再create table語句中使用engine=myisam來制定表的存儲引擎。Mysql和informateion_schema任然在使用myisam。對于grant表,不能轉化為InnoDB。
1.如果服務crash,在服務啟動後不需要做其他事情。InnoDB會自動recovery資料庫。
2.InnoDB buffer pool緩存表和索引,把資料和索引放在記憶體中可以提高處理速度。
3.放在不同表上的資料可以使用外鍵來關聯。
4.若資料在磁盤或者記憶體中損壞,checksume機制會警告你。
5.當每個表上都設計了合适的索引,設計的列都會被優化。
6.insert,update,delete會被change buffer機制優化。
7.性能不會因為giant表的long running query而限制。
1.指定primary key為最常用的列,若沒有可以用自增。
2.為了更好的join性能,外鍵定義在join字段上,并且保持字段資料類型一緻。
3.關閉自動送出,一次性送出可以提高性能。
4.可以使用start transaction commit包裹DML語句組成一個事務。
5.停用lock table語句,InnoDB可以控制多個會話在一個表上讀寫。
6.啟動innodb_file_per_table選項
7.InnoDB壓縮特性,row_format=compressed
8.—sql_mode-no_engine_substitution防止建立和指定engine不同的表。
1.可以壓縮索引和表。
2.可以建立,删除索引對性能和可用性影響變小。
3.truncate table很快,并且把空間還給OS,而不是保留在系統表空間中。
4.使用DYNAMIC行格式來儲存blob和text效率更高。
5.通過information_schema,檢視存儲引擎内部情況。
6.performance_schema檢視存儲引擎性能。
7.一些性能提升。
從之前版本更新MySQL 5.5之後,還是要檢查InnoDB是不是能夠正常在被程式使用。使用參數—default-storage-engine=Innodb設定預設存儲引擎。設定之後隻會影響後來建立的表。測試應用程式可以正常運作,确定讀寫正常,如果有依賴myisam特性可能會失敗。如果想要知道老表在innodb運作的情況,可以使用alter table table_name ENGINE=InnoDB。
或者
CREATE TABLE InnoDB_Table (...) ENGINE=InnoDB AS SELECT * FROM MyISAM_Table;
檢查InnoDB狀态:
1.使用SHOW ENGINE檢視所有MySQL所有的引擎,檢視DEFAULT列。
2.如果沒有InnoDB說明編譯的時候,沒有加InnoDB。
3.如果InnoDB存在但是不可用,回到配置檔案或者配置,去掉skip-innodb選項。
使用SHOW ENGINE檢視InnoDB是否存在來決定InnoDB是否可用。
如果你不要使用InnoDB:
1.使用—InnoDB=OFF或者—skip-innodb選項禁用innodb存儲引擎
2.因為innodb是預設的存儲引擎,是以啟動報錯,需要設定—default-storage-engine和—default-tmp-storage-engine,
3.為了讓服務在查詢information_schema innodb相關的表是不會奔潰,還需要配置一下參數
loose-innodb-trx=0
loose-innodb-locks=0
loose-innodb-lock-waits=0
loose-innodb-cmp=0
loose-innodb-cmp-per-index=0
loose-innodb-cmp-per-index-reset=0
loose-innodb-cmp-reset=0
loose-innodb-cmpmem=0
loose-innodb-cmpmem-reset=0
loose-innodb-buffer-page=0
loose-innodb-buffer-page-lru=0
loose-innodb-buffer-pool-stats=0
loose-innodb-metrics=0
loose-innodb-ft-default-stopword=0
loose-innodb-ft-inserted=0
loose-innodb-ft-deleted=0
loose-innodb-ft-being-deleted=0
loose-innodb-ft-config=0
loose-innodb-ft-index-cache=0
loose-innodb-ft-index-table=0
loose-innodb-sys-tables=0
loose-innodb-sys-tablestats=0
loose-innodb-sys-indexes=0
loose-innodb-sys-columns=0
loose-innodb-sys-fields=0
loose-innodb-sys-foreign=0
loose-innodb-sys-foreign-cols=0
ACID模式是資料庫設計的标準的集合。
A: atomicity原子性
C:consistency 一緻性
I:isolation 隔離性
D:durability 持久性
原子性
原子性主要由InnoDB事務來保持
一緻性
一緻性方面 ACID主要設計InnoDB内部處理來保護資料。
1.InnoDB雙寫 buffer
2.InnoDB災難恢複
隔離性
ACID的隔離性的模型,主要涉及InnoDB事務在指定隔離級别上的執行。
1.自動送出設定
2.set isolation level隔離級别
3.低級InnoDB鎖,可以通過INFORMATION_SCHEMA檢視。
持久性
ACID的持久性,涉及mysql和指定的硬體的互動,
1.innodb 雙寫
2.innodb_flush_log_at_trx_commit配置參數
3.sync_binlog 配置參數
4.innodb_file_per_table配置參數
5.儲存設備的,write buffer
6.儲存設備battery-backed cache
7.運作MySQL的作業系統,特别是支援fsync系統調用的
8.UPS支援的環境
9.備份政策
10.硬體裝置和網絡連接配接
在InnoDB事務模式,目标是把高性能的多版本的資料和2階段鎖定結合。InnoDB鎖定在行級别并且查詢預設以nolocking一緻性執行。和Oracle一樣。Lock資訊在InnoDB是空間高效實用的。鎖不需要建立。也不會照成記憶體壓力。
InnoDB所有使用者行為都在事務内。若打開了自動送出,每個SQL都是一個事務。預設會話都是自動送出的,若出錯會根據錯誤復原。自動送出的會話,可以通過start transaction 或者begin語句,以commit或者rollback結束,啟動一個事務。通過set autocommit=0取消自動送出。
預設InnoDB的隔離級别是REPEATABLE READ,InnoDB提供了4個隔離級别,READ UNCOMMITTED,READ COMMITTED,REPEATABLE READ和SERIALIZABLE。
使用者可以通過SET TRANSACTION語句設定隔離級别,使用—transaction-isolation選項來設定預設隔離級别。
對于行級鎖,InnoDB通常使用next-key鎖定。也就是說除了索引記錄,InnoDB還可以lock頁内空隙,不讓其他會話插入資料。Next-key lock是鎖定了index record和它之前的gap。
InnoDB實作标準的行鎖有2中強度類型,S鎖和X鎖。粒度類型有3類,record鎖,gap鎖,next-key鎖。
InnoDB可以支援多粒度鎖定允許,就引入了意向鎖。
IS:事務T意向在表上使用S鎖。
IX:事務T以上在表上使用X鎖。
意向鎖協定:
1.為了擷取在行上擷取S鎖,就必須在表上擷取IS鎖。
2.為了擷取行上的X鎖,必須在表上限擷取IX鎖。
Lock相容表
X
IX
S
IS
Conflict
Compatible
略
一緻性讀的意思是,InnoDB使用多版本來生産查詢結果的快照。查詢隻能看到事務啟動時,已經送出完的事務修改。有個異常就是查詢可以看到事務内前面語句的修改内容。這個異常會導緻一個情況,在其他事務剛好也更新了同樣的表,這種情況下,你看到的表狀态重來就沒出現在資料庫過。
如果隔離級别是所有的一緻性讀,從第一個讀開始。
使用READ COMMIT隔離級别,每個事務中的一緻性讀來至于自己重新整理的快照。
不管是READ COMMIT,REPEATABLE READ都預設使用一緻性讀。一緻性讀不會鎖定表通路,是以其他會話可以同時更新這些表。
假設你預設是REPEATABLE READ隔離級别。當查詢資料是會給一個時間點,當行被其他事務删除,在查詢不會發現行被删除。
Note
快照在事務内有效。盡管查不到資料,但是update,delete還是可以修改這些資料庫的。
SELECT COUNT(c1) FROM t1 WHERE c1 = 'xyz'; -- Returns 0: no rows match.
DELETE FROM t1 WHERE c1 = 'xyz'; -- Deletes several rows recently committed by other transaction.
SELECT COUNT(c2) FROM t1 WHERE c2 = 'abc'; -- Returns 0: no rows match.
UPDATE t1 SET c2 = 'cba' WHERE c2 = 'abc'; -- Affects 10 rows: another txn just committed 10 rows with 'abc' values.
SELECT COUNT(c2) FROM t1 WHERE c2 = 'cba'; -- Returns 10: this txn can now see the rows it just updated.
如果要推進快照點,可以執行事務送出,再執行另一個select或者START TRANSACTION WITH CONSISTENT SNAPSHOT。
如果想要看最新的資料庫狀态,可以使用read committed,或者鎖定讀。
SELECT * FROM t LOCK IN SHARE MODE;
使用READ COMMITTED隔離級别,事務裡面的每次一緻性讀都是獨自己重新整理的快照。使用LOCK IN SHARE MODE,發生讀鎖。
一緻性讀不能覆寫DDL語句,insert into select ,update…(select),create table select都不能指定for update或者 lock in shared mode。
在事務裡select不會被保護,其他事務可以同時修改查詢的值。Innodb提供額外的鎖讀,提供安全性:
1.Select … lock in share mode設定
2.select … for update
使用以上标記的鎖,到事務完成時才能釋放。
InnoDB有幾類鎖:record lock,Gap lock,Next-key lock
Record Lock鎖定Index記錄,不管有沒有定義索引。
預設,InnoDB使用REPEATABLE READ隔離級别并且innodb_locks_unsafe_for_binlog不可用。Next-key lock查詢可以防止幻讀出現。
Next-key是index-row和gap的組合。Next-key鎖定record和,record之前的gap。若會話共享,獨占鎖定了R,那麼另外一個就不能再R之前插入資料。
Gap lock不會使用在使用唯一索引查詢上。
有一種gap lock類型被稱為插入意向gap lock,由Insert操作設定。這個鎖表示嘗試插入。多事務插入到同一個index gap就會被堵塞。
使用read commit或者 innodb_locks_unsafe_for_binlog來取消gap lock。
幻影問題,事務内相同查詢在不同時間運作,傳回的資料不一樣。
如:
SELECT * FROM child WHERE id > 100 FOR UPDATE;
如果不加gap鎖,就可以插入101,那麼再次使用查詢,就會出現幻影行。
為了避免幻影問題,使用next-key lock鎖定index record和gap。
鎖讀,update,delete,當掃描是,會對所有的掃描到的index record上鎖。并不會理睬是不是在where條件之外。InnoDB隻知道要掃描的Index Range。
InnoDB指定lock類型:
1.select from 一緻性讀不加鎖,除非在SERIALIZABLE隔離級别
2.select from lock in share mode 共享鎖讀,next-key lock。
3.select from for update 排他鎖讀
4.update where排他的next-key lock
5.delte from where排他next-key lock
6.insert在插入的行上設定排他鎖,是record鎖,不是next-key鎖。
如果發生重複鍵錯誤,那麼index record會設定共享鎖,當多個事務同時獲得共享鎖,就有可能會出現死鎖。
CREATE TABLE t1 (i INT, PRIMARY KEY (i)) ENGINE = InnoDB;
Now suppose that three sessions perform the following operations in order:
Session 1:
START TRANSACTION;
INSERT INTO t1 VALUES(1);
Session 2:
Session 3:
ROLLBACK;
當第一個在會話1執行,那麼會話2和會話3會報主鍵沖突,會共享鎖。當會話1釋放。會話2,會話3同時去擷取排他鎖。就會導緻2,3死鎖。
7.Insert on duplicate key upate,和insert不同,當出現重複鍵錯誤,或使用x鎖,不是s鎖。
8.replace當在沒有沖突的情況下,和insert一樣。如果有沖突擷取next-key x鎖,替換行。
39insert into t select * from s where,會在T中設定record x鎖。若隔離級别是read committed或者設定了innodb_locks_unsafe_for_binlog,并且不是SERIALIZABLE否則innodb設定共享next-key鎖在S表上。
Create table select,insert select都會申請共享next-key鎖。如果表在結構replace into t selct from s where 或者update t where col in(select from s)innodb都會在s上設定共享next-key鎖。
10.在初始化auto_increament時,會在相關的索引上加上x鎖。在通路自增counter時,使用auto-inc鎖,語句執行完就釋放。
11.如果表上定義了外鍵,任何寫入操作都需要去檢查行,需要設定共享行鎖檢視。
12.lock tables設定表鎖
Innodb自動死鎖診斷,不會發現設計到table locks的死鎖。因為table locks是mysql層的不知道innodb的行級别鎖。
預設MySQL啟動會話,以自動送出方式送出事務。如果語句傳回錯誤,會根據錯誤處理commit和rollback。
如果會話取消了自動送出,沒有顯示送出,最終會復原。一些語句會影響事務送出,在commit執行的話,會導緻影響事務送出。
InnoDB自動診斷發現事務死鎖復原事務或者打破事務復原。
如果配置innodb_table_locks=1預設并且autocommit=0 InnoDB會認識table locks否則不認識。
在InnoDB中一個事務rollback,所有的鎖都會被釋放。然而對于單個語句因為出錯rollback,可能鎖會被保留,因為InnoDB不知道鎖是屬于哪個語句的。
如果select調用了使用者函數在事務中,語句出錯,語句被復原。
死鎖是事務資料庫的典型問題,除非經常發生,不然不是問題。在寫程式的時候要進行重試。
InnoDB使用自動行鎖。在單行寫入也可能發生死鎖,因為不是真的原子性。他們自動在index record上設定鎖。
可以使用如下方法來減少死鎖:
1. 任何時候,可以使用show engine innodb status來确認最近死鎖。
2. 使用innodb_print_all_deadlocks,把錯誤資訊print到error log上。
3. 發生錯誤的時候要重試
4. 完成修改後,立馬送出
5. 如果使用鎖讀,使用比較低的隔離級别,比如read committed
6. 當修改不同的表,或者不同的行集,使用一緻的順序。
7. 增加合适的索引。
8. 減少鎖,如果可以使用老的快照,就不要使用鎖讀。
9. 如果還是沒有緩減,使用串行事務,表級鎖。
10. 另外一個方式是建立一個輔助的信号量表。事務update先要通路信号量表。
InnoDB是多版本存儲引擎,儲存了老的修改的行。支援并發和復原。這些資料被儲存在rollback segment。InnoDB使用在rollback segment的資訊來執行undo。
内部,InnoDB為每個行存儲增加了3個列。6個位元組的DB_TRX_ID表示最後寫入的事務ID,7位元組DB_ROLL_PTR roll指針,roll指針指向rollback segment中undo log record。6位元組的DB_ROW_ID,包含rowid,rowid是單調遞增的。
undo log在rollback segment被分為insert,和update undo log。insert undo log隻在復原時需要commit才能釋放。update undo logs也可以用在一緻性讀上,隻有在事務沒有使用的時候才會消失。
InnoDB不能從update undo log中放資料,復原段會變得很大。undo log記錄在復原段是一般比insert和update的行小。
在InnoDB多版本結構,一個行不會在删除後,馬上實體上删除。隻有當取消update undo log記錄後才會在實體上删除。删除操作被稱為清空,通常清空的順序和sql順序一樣。
如果insert和delete行。
如果你插入和删除行在小批處理。清理現場會滞後會越來越大導緻變慢。這時,可以使用innodb_max_purge_lag參數來調整清理操作。
MySQL以.frm檔案方式,把資料目錄儲存在資料庫目錄中。InnoDB也會把表的中繼資料資訊存放在表空間中。當MySQL drop表或者資料庫,會删除一個或者多個.frm檔案。但也不能通過移動.frm檔案來移動表。
每個InnoDB表有一個特别的聚集索引,聚集索引和primary key同義。
1. 當你定義了primary key,InnoDB會作為聚集索引。
2. 如果沒有定義primary key,MySQL會使用unique,并且非null的列作為聚集索引
3. 如果表沒有primary key和unique索引,InnoDB自動生成一個隐藏聚集索引聚合列和rowid。
如果通過通路聚集索引通路一行很快是因為開銷索引查詢可以直接通路到有所有資料的page。如果表很大,通過聚集索引通路會減少I/O。
除了聚集索引外,其他都是secondary索引,InnoDB secondary 索引,都包含了primary key的列。如果primary key很長,secondary就需要更多的空間,是以建議primary key比較短。
所有InnoDB是以是b樹結構,索引的page為16KB,當新的記錄插入,InnoDB試圖保留1/16的空間用于未來的插入和修改。
如果index record是順序插入的,page為15/16,若是随機插入的1/2~15/16。當page低于1/2,page會試圖調整釋放page。
page的大小可以通過參數innodb_page_size制定。
資料庫應用程式總是以主鍵自增的循序插入新行,因為聚集索引和primary key順序一樣,插入table不需要做随機I/O。
secondary index是不唯一的,insert到secondary順序是随機的。删除和update會影響資料頁是随機的。
當索引被删改,innodb會檢查page是否在buffer pool。如果在,會直接修改index page,如果不在,InnoDB會記錄到insert buffer中。insert buffer會保持的很小,可以放到buffer pool,修改會快速修改。這個程序被稱為change buffering。
定期,insert buffer會合并到secondary index上,通常吧多個修改合并到一個page,來減少I/O操作。
insert buffer在事務送出後,會合并到insert buffer。當很多索引要被delete和update,insert buffer合并會話很長時間。這個時候磁盤I/O會增長,會導緻依賴于磁盤查詢延遲。另外一個重要I/O操作時清理線程。
自适應hash索引讓innodb很像記憶體資料庫,适應負荷和記憶體。不會犧牲任何事物特性和可靠性,使用innodb_adaptive_hash_index來啟動和禁用。
根據查詢部分,mysql建立一個hash索引使用固定的索引鍵。固定鍵的長度可以是任意長度的。隻有btree的一些值會出現在hash索引上。hash索引隻會的page進行通路。
當表整個放入住記憶體,hash index可以加快通路速度。innodb有機制可以監控索引通路。如果InnoDB覺得查詢可以從建立hash index後獲得好處,就會自動建立。
在某些情況下,hash索引查找提高的速度遠遠大于額外的監控的和維護hash索引結構。有時候,read/write鎖守護資料在搞負荷情況下,會變成争用焦點。
你可以使用show engine innodb status的semaphores段來監控hash index。若看到大量的RW-latch在btr0sea.c被建立,可能取消自适應hash索引更好。
實體行結構依賴于InnoDB表依賴于表建立時候的row format。可以使用show table status檢查。
InnoDB表空間和日志檔案概述
2個重要的磁盤管理的資源是,InnoDB的資料檔案和日志檔案。如果沒有InnoDB選項。MySQL建立自動擴充的檔案大于12MB,ibdata1和2個日志檔案ib_logfile0,ib_logfile1。大小由innodb_log_file_size系統參數。
考慮儲存設備
把log檔案放到不同的磁盤可以提升性能。也可以使用原始的磁盤分區作為innodb資料檔案,可能可以提升性能。
指定innodb表空間位置和大小
innodb_data_file_path選項指定了資料檔案,使用分号隔開。
innodb_data_file_path=datafile_spec1[;datafile_spec2]...
以下設定顯示的建立最小系統表空間
[mysqld]
innodb_data_file_path=ibdata1:12M:autoextend
若指定了autoextend InnoDB會自動擴充。max指定檔案最大限制
innodb_data_file_path=ibdata1:12M:autoextend:max:500M
innodb_data_home_dir指定了表空間檔案的路徑
innodb_data_home_dir = /ibdata
innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend
innodb不會建立目錄是以要保證,目錄存在。并且保證有權限。
innodb_data_home_dir預設值為mysql 資料目錄。
也可以直接在innodb_data_file_path上指定檔案路徑。
建立InnoDB系統表空間
當建立系統表空間時,最好使用指令行啟動。
C:\> "C:\Program Files\MySQL\MySQL Server 5.6\bin\mysqld" --console
如果MySQL資料目錄在隻讀媒體中,帶—innodb-read-only來啟動服務。就可以查詢了。
準備隻讀操作,首先要保證資料被重新整理到資料檔案中。然後取消change buffer innodb_change_buffering=0,使用slow shutdown。使用參數—innodb-read-only =1。
1.有一部分資料在隻讀媒體中
2.多個MySQL執行個體并發查詢相同的資料目錄
3.因為資料安全或者資料內建的需要設定為隻讀
如果MySQL啟動了—innodb-read_only選項,InnoDB會關閉一些特性群組件:
1.沒有啟動change buffer
2.啟動階段沒有carsh recovery
3.因為隻讀不需要redo log,可以把redo log 設定到最小
4.素有背景IO除了IO都可以關閉
5.deadlock,monitor輸出等等都不會被寫入臨時檔案。Show engine innodb status不會輸出任何資訊。
6.如果Mysql以—innodb-read-only啟動,如果資料目錄放在讀寫上,還是可以運作DCL指令grant,revoke。
7.修改配置選項可以修改寫入操作,當read-only時,沒有影響。
8.MVCC強制隔離級别被關閉
9.undo log不能使用。
InnoDB管理設定到很多方面:
1.管理資料檔案表示系統表空間,innodb表和其他相關的索引
2.管理redo log檔案
3.盡量使用innodb
4.性能相關的通用管理
啟動前,先檢查innodb資料檔案存在,并且有足夠的權限通路。第一次啟動使用指令行比較好。因為會把資訊都print到指令行上。
File-Per-Table的好處:
1.當表删除或者truncate,空間可以被OS回收。
2.Truncate table在單個.ibd檔案上執行更快。
3.可以為每個表指定一個特定存儲。優化IO,空間管理。CREATE TABLE ... DATA DIRECTORY =absolute_path_to_directory。
4.運作OPTIMEIZE TABLE,壓縮或者重建建立表空間。運作OPTIMIZE TABLE InnoDB會建立一個新的ibd檔案。當完成時,老的表空間會被新的代替。
5.可以移動單個表,不需要移動整個資料庫
6.可以把表複制到另外一個執行個體
7.innodb_file_per_table啟動後才能使用Barracuda檔案格式。
8.可以更有效的存儲帶BLOB,TEXT使用動态行模式的表。
9.使用innodb_file_per_table可以提高recovery的成功率,減少損壞錯誤發生恢複的時間。
10.可以快速的備份,恢複單個表。
11. innodb_file_per_table 可以從備份中去除一個表
12. innodb_file_per_table在備份和複制表時,容易觀察每個表的狀态。
13.可以通過檔案系統直接觀察表的大小。
14.當innodb_flish_method設定為O_DIRECT,通常linux檔案系統不允許并發的寫入同一個檔案。使用innodb_file_per_table就會有性能提升。
15.不啟用innodb_file_per_table,資料都會放在系統表空間中,最大64TB,如果使用innodb_file_per_table每個表可以64TB。
File-Per-Table一些缺點:
1.表空間中的空間隻能被這個表使用
2.fsync操作必須在每個表上都運作一遍
3.mysqld必須保持一個打開的檔案句柄,表太多會影響性能。
4.會消耗很多檔案描述
5. innodb_file_per_tablezhiyou 5.6.6或更高版本才能用,有向下相容問題。
6.如果很多表都增長,會出現檔案碎片問題。導緻drop 表和表掃描性能下降。
7.當drop表的時候會掃描buffer pool,如果太大會比較耗時。
8.innodb_autoextend_increment指定當檔案滿了之後增長的空間。
File-Per-Table啟動禁用方式:
設定配置檔案或者全局變量:innodb_file_per_table。
啟動innodb_file_per_table,InnoDB會吧資料存放在ibd檔案中,和MyISAM不通,MyISAM存放在tbl_name.myd,tbl_name.myi。
InnoDB的資料和索引都放在ibd檔案中,frm檔案依然還是會建立。如果關閉innodb_file_per_table那麼InnoDB的表都會建立在系統表空間中。
通過以下方法可以移動innodb到自己的表空間:
-- Move table from system tablespace to its own tablespace.
SET GLOBAL innodb_file_per_table=1;
ALTER TABLE table_name ENGINE=InnoDB;
-- Move table from its own tablespace to system tablespace.
SET GLOBAL innodb_file_per_table=0;
啟動了innodb_file_per_table,可以再建立表的時候指定檔案路徑。具體看create table。
這個位置很重要,因為之後不能通過alter table修改。在資料目錄上,MySQL在目标目錄上建立一個以資料庫命名的子目錄,裡面存放新的ibd檔案。在DataDir上建立一個tbl_name.isl檔案,包含了這個檔案的路徑。這個檔案相當于symbolic link。
1.MySQL初始化的時候會把ibd檔案保持打開裝填,以防止裝置被unmount。不要在mysql運作的時候unmount,不要在unmount的時候啟動服務。
2.不要把Mysql表放在NFS mounted卷上。NFS使用消息來修改檔案,如果消息不對,可能會影響資料一緻性。
3.如果使用LVM快照,file copy,或者基于檔案的備份,先執行FLUSH TABLS FRO EXPORT.
4.data directory子句可以使用symbolic link來代替。
表空間複制的限制和注意點
1.表空間複制過程隻有當innodb_file_per_table啟用的時候才能用。
2.隻有讀操作可以再該表上使用。
3.導入時,page size必須和被導入執行個體上的一緻。
4.DISCARD TABLESPACE不支援分區表。
5. DISCARD TABLESPACE有主外鍵限制的也不支援,在discard之前要先設定foreign_key_checks=0。
6.alter table import tablespace不會強制外鍵限制
7.alter table import tablespace 不需要cfg檔案,但是當沒有cfg檔案的時候導入時不會檢查中繼資料。
8.MySQL 5.6之後,如果2個服務都是GA狀态,并且在一個系列裡面,可以導入。否則不許先在沒導入服務上建立檔案。
9.在windows上innodb,表空間,表名都是小寫,為了避免這個問題,要注意linux,unix上的大小寫。
例子:移動表空間到另外一個服務上
1. 源伺服器上建立建立表:
mysql> use test;
mysql> CREATE TABLE t(c1 INT) engine=InnoDB;
2. 在目标伺服器上建立表,如果不存在:
3. 目标伺服器上discard表
mysql> ALTER TABLE t DISCARD TABLESPACE;
mysql> FLUSH TABLES t FOR EXPORT;
cfg檔案被建立在資料目錄上.
5. 複制ibd和cfg檔案:
shell> scp /path/to/datadir/test/t.{ibd,cfg} destination-server:/path/to/datadir/test
6. Unlock 表釋放flush table for export的鎖:
mysql> UNLOCK TABLES;
7. 導入到目标服務:
mysql> ALTER TABLE t IMPORT TABLESPACE;
表空間複制内部細節
當運作alter table discard tablespace,目标服務:
1.表會被X鎖
2.表空間會被分離
當運作flush tables for export:
1.表被S鎖
2.清理線程停止
3.髒資料被同步到磁盤
4.表中繼資料生産到cfg檔案
當運作unlock tables
1.cfg被删除
2.s鎖被釋放,清理線程啟動
當運作alter table import tablespace:
1.檢查表空間page是否損壞
2.空間Id和LSN被更新
3.檢查flag,LSN被更新
4.b樹被更新
5.page設定為dirty,讓資料庫可以寫入磁盤。
你可以把undo log分離到獨立的表空間檔案。詳細看14.13.16
MySQL 5.6.8之後,修改innodb日志檔案和大小:
1.沒有錯誤下,關閉服務。
2.編輯my.cnf,設定innodb_log_file_size,innodb_log_files_in_group
3.啟動服務。
當innodb 發現innodb_log_file_size和老的不一樣。會删除redo log檔案,建立新的檔案。
MySQL 5.6.7和之前的版本,修改innodb檔案個數和檔案大小:
1.設定innodb_fast_shutdown 為1
2.關閉服務沒有錯誤
3.複制老的日志檔案到其他地方
4.在目錄中删除日志檔案
5.編輯配置檔案
6.啟動服務
增加InnoDB表空間
最簡單的方法是通過自增長來實作,innodb_autoextend_incremnt參數。也可以通過增加新的檔案方式來擴充空間:
1.關閉服務
2.若之前的檔案定義了自增長,修改變為固定長度,設定大小。可以再參數innodb_data_file_path中顯示指定。
3.在innodb_data_file_path後增加新的檔案,可以設定為自增長。
4.啟動服務。
innodb_data_home_dir =
innodb_data_file_path = /ibdata/ibdata1:10M:autoextend
一段時間之後,檔案增長到了988M。
innodb_data_file_path = /ibdata/ibdata1:988M;/disk2/ibdata2:50M:autoextend
減少InnoDB表空間
減少innodb表空間過程:
1.使用mysqldump,導出所有innodb表包括在mysql資料庫中的表。
2.停止服務
3.删除所有存在的ibd檔案,ibdata,ib_log
4.删除frm檔案
5.配置新的表空間
7.導入檔案。
你可以把系統表空間放到原生分區中。當使用原生磁盤分區,保證服務有讀寫分區的權限。
在Linux和unix系統配置設定原生磁盤分區
1.當你建立一個新的資料檔案,指定在innodb_data_file_path選項設定newraw
innodb_data_home_dir=
innodb_data_file_path=/dev/hdd1:3Gnewraw;/dev/hdd2:2Gnewraw
2.重新開機服務,InnoDB注意到newraw關鍵字,并初始化這個行分區,不建立或者修改任何InnoDB表。否則下次重新開機InnoDB會重新初始化修改會丢失。
3.InnoDB初始化新分區之後,停止服務,把newraw修改為raw。
innodb_data_file_path=/dev/hdd1:3Graw;/dev/hdd2:2Graw
4.重新開機服務,InnoDB允許修改。
建立表
-- Default storage engine = InnoDB.
CREATE TABLE t1 (a INT, b CHAR (20), PRIMARY KEY (a));
-- Backward-compatible with older MySQL.
CREATE TABLE t2 (a INT, b CHAR (20), PRIMARY KEY (a)) ENGINE=InnoDB;
根據innodb_file_per_table設定,InnoDB建立每個表在系統表空間或者獨立的表空間,使用show table status語句檢視這些表的屬性:
mysql> SHOW TABLE STATUS FROM test LIKE 't%' \G;
*************************** 1. row ***************************
Name: t1
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 0
Avg_row_length: 0
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: NULL
Create_time: 2015-03-16 16:26:52
Update_time: NULL
Check_time: NULL
Collation: latin1_swedish_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.00 sec)
使用新的行模式
SET GLOBAL innodb_file_format=barracuda;
CREATE TABLE t3 (a INT, b CHAR (20), PRIMARY KEY (a)) ROW_FORMAT=DYNAMIC;
CREATE TABLE t4 (a INT, b CHAR (20), PRIMARY KEY (a)) ROW_FORMAT=COMPRESSED;
為primary key設定主鍵,列的選擇:
1.被很多查詢引用
2.左邊無空白
3.不會有重複鍵
4.一旦插入後很難修改
為了跨平台移動,建立的資料庫和表使用小寫。在配置檔案中設定
lower_case_table_names=1
使用flush tables for export準備innodb表複制到另外一個服務。當然InnoDB必須開啟innodb_file_per_table
可以使用InnoDB資料庫,簡單的複制所有相關檔案。像MyISAM資料檔案,InnoDB資料和日志檔案是binary,所有的平台都相容。
當移動ibd檔案,資料庫目錄名必須相同。如果你有幹淨的ibd檔案備份,你可以恢複到新裝MySQL:
1.複制ibd之後,不要drop或者truncate,因為這樣會修改表空間中存在的表ID。
2.alter table删除中繼資料
ALTER TABLE tbl_name DISCARD TABLESPACE;
3.複制ibd檔案到目标庫中
4.使用alter table語句導入中繼資料
ALTER TABLE tbl_name IMPORT TABLESPACE;
幹淨的ibd檔案備份要滿足一下條件:
1.沒有未送出的修改。
2.沒有未合并的insert buffer
3.清理所有删除标記的index record
4.把所有修改也從buffer pool寫入到檔案中。
使用以下步驟建立幹淨的ibd備份。
1.停止所有活動并送出所有事務
2.等待直到show engine innodb status沒有活動,主線程的狀态為waiting for server activity。
另外一個方式是:
1.使用Mysql企業版備份備份mysql
2.啟動mysqld服務,清理ibd檔案。
導入導出
可以使用mysqldump導出表,然後在另一個表上導入。在導入時關閉自動送出可以提高性能。
連接配接到MySQL預設是自動送出模式。多餘多語句事務,可以set autocommit=0取消自動送出。使用start transaction開啟,commit,rollback結束。
從MyISAM中過渡,減少key_buffer_size配置釋放記憶體。增加innodb_buffer_pool_size配置。
1.盡可能的多配置設定記憶體,最多80%的記憶體
2.當os總是出現記憶體短切,減少innodb_buffer_pool_size
3.若innodb_buffer_pool_size有好幾個G可以使用innodb_buffer_pool_instance增加buffer pool,減少通路buffer pool的沖突。
4.在忙綠服務,把query cache關閉。
因為MyISAM不支援事務,是以不用在意自動送出。主要是用在innodb上的。當大量的寫入的服務上,若事務太長會生成大量的負荷。是以小心避免事務運作時間太長:
1.如果你使用mysql互動式會話,完成的時候總是使用commit,rollback。及時關閉互動式會話。
2.保證任何錯誤,rollback不完整修改或者commit完整送出
3.ROLLBACK是比較昂貴的操作。當處理大量資料後,避免執行rollback
4.大量批量insert語句,同期的commit可以提高性能。
事務太長,會浪費記憶體和磁盤空間。事務太短,因為commit太頻繁,也會浪費I/O。對于1.頻繁使用InnoDB表,應該取消自動送出避免不必要的I/O。
2.自動送出适合與生産報表或者分析統計。
3.如果做了一列相關修改,最後要使用一個commit。
4.select語句也會打開一個事務。
MySQL會很快發現死鎖并且取消小的事務。應用應該處理錯誤并重新開機事務。如果死鎖發生很頻繁,就要檢查應用程式代碼,整理代碼順序,或者縮短事務。Innodb_print_all_deadlock會吧錯誤資訊輸出到error log中。
為了獲得做好的性能,需要調整幾個和存儲有關的參數。當你轉化一個MyISAM表,資料大,通路頻繁,并且重要的。可以考慮innodb_file_per_table,innodb_file_format和innodb_page_size配置,和create table中的row_format,key_block_size。最重要的參數是innodb_file_per_table。
使用alter指令轉換
使用show create table table_name 擷取表結構,然後修改engine子句。
把資料轉移到空的innodb表,可以使用:
INSERT INTO innodb_table SELECT * FROM myisam_table ORDER BY primary_key_columns.
可以再插入之後在建立索引,以前索引建立是很慢的,現在消耗已經降低。如果有唯一性限制,可以先關閉限制檢查,提高插入性能
SET unique_checks=0;
... import operation ...
SET unique_checks=1;
對于達标,可以減少I/O因為innodb可以使用insert buffer來批量寫入secondary index的修改。
對于大表也可以使用如下來控制insert
INSERT INTO newtable SELECT * FROM oldtable
WHERE yourkey > something AND yourkey <= somethingelse;
不管是轉化MyISAM到InnoDB,都要保證有足夠的空間存放新老2份資料。如果alter table出現空間不足,會復原,并且化很長時間。Innodb使用insert buffer批量合并到index rolback沒有這樣的機制,會比insert多近30倍的時間。
Primary key是總要的因素,會影響mysql查詢性能和表索引空間使用。
建立primary key的指導:
1.為每個表定義主鍵
2.最好在建立表的時候就定義,而不是使用alter table
3.仔細的選擇列和資料類型,最好使用數值列
4.如果沒有合适的列,考慮自增列
5.如果不再到主鍵會不會被修改的情況下,自增列也是很好的選擇。
根據表的預計大小,使用最小的類型,可以讓表收窄減少空間,若有secondary索引,可以減少索引空間。
建立表,沒有指定主鍵,mysql會自動建立一個6位元組長度的主鍵,但是不能用于查詢。
額外的可用性和擴充性,需要的空間比MyISAM多。可以窄設計來節省空間。
InnoDB檔案需要比MyISAM更加小心,有計劃性:
1.不能删除innodb系統表空間
2.複制innodb到另外一個服務,需要使用flush table for export并且複制cfg和ibd檔案。
InnoDB對自增列的插入做了優化。InnoDB表的自增必須是索引的一部分。
若在InnoDB上使用了自增,InnoDB資料目錄包含auto-increment計數器。用來配置設定自增值,計數器儲存在記憶體中,不是在磁盤中。
InnoDB初始化自增計數器,服務啟動後,第一個插入的語句會運作如下語句:
SELECT MAX(ai_col) FROM table_name FOR UPDATE;
InnoDB增加這個值,并配置設定給counter和這個insert。預設增加為1,可以通過auto_increment_increment來配置。
若表是空的,就使用1,可以用auto_increment_offset來設定便宜。
若在初始化錢使用了語句show table status,innodb初始化計數器,但不增加。初始化使用排它鎖。
在初始化之後,如果不顯示的指定值,自增計數器會配置設定一個值。如果指定的值大于計數器,計數器就會被更新。如果為自增列指定了null或者0,innodb會為自增配置設定一個新值。
通路計數器,會使用auto-inc鎖,知道語句結束才釋放。Auto-inc提高了并發性,但是長期持有會導緻性能問題。如:
Insert into t select from t1;
服務重新開機後,第一次插入會初始化自增計數器,也會取消create table中auto_increment設定。
若事務rollback,計數器不會rollback。
InnoDB的自增使用特殊的鎖AUTO-INC。語句結束就釋放。對于基于語句的複制,意味着slave,master使用想用的語句,會導緻insert語句不确定。
有表如下:
CREATE TABLE t1 (
c1 INT(11) NOT NULL AUTO_INCREMENT,
c2 VARCHAR(10) DEFAULT NULL,
PRIMARY KEY (c1)
) ENGINE=InnoDB;
插入資料
Tx1: INSERT INTO t1 (c2) SELECT 1000 rows from another table ...
Tx2: INSERT INTO t1 (c2) VALUES ('xxx');
InnoDB不知道有多少行要通過select插入。在語句執行是一個一個的配置設定。Tx1生産的自增時連續的,Tx2配置設定的自增,和Tx1比大小,由誰先運作決定。
隻要執行順序和binary log一樣,結果是一樣的。是以在插入的時候可以使用表鎖,這樣自增配置設定對複制來說是安全的,然而當有多個會話insert時表鎖會影響并發性和可擴充性。
如果沒有加表鎖,那麼tx1和tx2配置設定的自增将是不确定的。有類insert事先知道插入的行數,就可以避免表級auto-inc鎖,任然可以保證給予語句複制的安全性。如果不需要使用binlog來恢複或者複制,可以取消表級auto-inc鎖來提高性能。但是會出現自增值是交錯的。
對于可以知道insert行數的InnoDB可以快速配置設定值,而不用加鎖,前提是auto-inc沒有配置設定。這些insert語句擷取自增值是有mutex控制,配置設定過程完成就釋放。
新的鎖機制可以提高可擴充性,但是和之前比原理有些不同,可以通過參數innodb_autoinc_lock_mode配置.insert因為auto-inc鎖定的問題被分為幾類:
Insert-like:
所有在表上生成新行的語句,insert,insert select,replace,replace select,load data
Simple insert:
行插入可以預知行數。Insert on duplicate key update除外。
Bulk insert:
插入行數無法預知,insert select,replace select,load data。
Mixed-Mode Insert:
其實是simple insert 但是中間有些指定的自增列
INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');
有以下一些取值:
0:傳統鎖模式,所有的insert-like語句都擷取auto-inc鎖保持知道語句結束
1: 連續鎖模式,bluk insert語句會使用auto-inc鎖,simple-insert可以使用輕量的mutex。但是如果有語句使用了auto-inc就要鎖釋放。配置設定的自增值都是順序的。對于mixed-mode insert因為使用者指定,是以會配置設定比需要的更多的自增。
2:交錯鎖模式,多個語句可以同時執行,但是對于給予語句的複制是不安全的。
Innodb_autoinc_lock_mode對其他使用的影響:
在複制中自增:如果使用基于語句的複制,建議設定為1,0,保證自增值确定性。
丢失自增值和順序空隙:在所有的模式下,如果事務復原,都會導緻自增值丢失。
Bulk insert自增值空隙:在1,0下自增值配置設定是順序的。沒有空隙,但是如果為2,bluk insert和insert like語句一起執行的時候就可能會出現空隙。
Mixed-mode insert自增值的配置設定:因為混合模式,有些會指定自增,有些不會。語句在不同鎖定模式下,反應也不同:
Innodb_autoinc_lock_mode = 0
+-----+------+
| c1 | c2 |
| 1 | a |
| 101 | b |
| 5 | c |
| 102 | d |
下一個值是103
Innodb_autoinc_lock_mode = 1
下一個值是105而不是103
Innodb_autoinc_lock_mode = 2
| x | b |
| y | d |
X,y是唯一的大于之前生成的任何行。
如果下一個自增時4,那麼上面insert語句就會報錯,建沖突。因為5會配置設定給b,和c沖突。
不要把MySQL資料庫上的表轉移到InnoDB上,不支援。一旦轉化後,MySQL不能重新開機除非還原到以前的備份。不要把InnoDB表建立在NFS上。
1.一個表最多能夠包含1017個列
2.最多能有64個secondary 索引
3.單列索引,key的長度最多隻能767個位元組,使用innodb_large_prefix可以突破767的限制最多為3072.如果再複制情況下,如果slave不能設定,master也不要設定
4.InnoDB最大key長度為3500,但是MySQL限制到3072位元組
5.若page size奢侈為8KB或者4KB對應的index key也會按比例收縮:
16KB->3072B,8KB->1536B,4KB->768B
6.最大行長度,也會根據page size變化而變化
16KB->8000B,8KB->4000B,4KB->2000B
7.在老的作業系統上,檔案做多為2GB。
8.innodb 日志檔案最多為512GB。
9.表空間最小為10MB,最大為64TB,也是表做大的大小。
10.預設資料庫page size為16KB。
1.全文索引
2.InnoDB支援空間資料類型,但是不能建立索引
1.通過analyze table确定索引中資料密度。,analyze table随機采樣并且更新表的評估值。
當啟動innodb_stats_persistent啟動,要在大量修改之後運作analyze table,因為啟動後,統計資訊不會被定期計算。
在生産統計資訊是,可以通過innodb_stats_persistent_sample_page修改采樣率,或者使用innodb_stats_transient_sample_pages。
若join優化器優化有問題,可以使用analyze table重新分析。也可以使用force index強制縮影使用。也可以通過變量max_seeks_for_key,設定最大seek,超過就變掃描。
2.若語句或者事務在一個表上運作,并且有一個analyze table運作,後面還跟了一個analyze table。那麼第二個analyze table就會被堵塞。直到語句或者事務完成。因為analyze table 運作完成必須要标記目前加載的表定義過期。新的事務或者語句必須加載新的表定義。在目前事務沒有完成前老的表定義不能被清理。
3.show table status不能提供準确的統計資訊,隻能看被表保留的實體空間。InnoDB内部不儲存行數。準确的行數需要count,若不需要太準确可以使用show table status的結果。
4.在windows平台上,innodb資料庫和表名内部都用小寫儲存
5.auto_increment列必須為索引的一部分
6.在auto_increment初始化的時候,innodb會在和自增列相關的索引尾上加一個排它鎖。當通路auto-increment列時innodb使用特定的auto-inc鎖,直到語句完成。
7.當重新開機mysql服務,innodb可能重用老的值,因為配置設定後沒有被儲存到表裡面。
8.當auto_increment超出之後的insert會報錯重複key錯誤。
9.delete from table_name 不會重新生成表,是删除所有行。
10.外鍵的級聯操作,不會觸發觸發器
11.不能建立列和innodb内部列一樣的名字。
1.在MySQL層lock table會鎖定MySQL層,也會請求InnoDB 表鎖。如果innodb_table_locks=1,lock tables會申請mysql層的表鎖和innodb的表鎖。如果為0不需要申請innodb的表鎖。在沒有innodb表鎖情況下,lock tables在其他事務在表上鎖定了一些記錄的時候,也可以成功鎖定。
2.innodb鎖在事務内有效,事務結束後釋放。
3.不能再事務中鎖定其他表,因為lock tables會隐式執行commit和unlock tables。
4.從1023并發事務修改,被更新到128*1023,同僚寫入undo record.
使用SQL文法和MySQL配置,可以建立壓縮儲存資料的表。壓縮可以提高原裝置的性能和可擴充性。壓縮也表示記憶體和磁盤傳輸變小。占用的空間變小。
InnoDB可以建立壓縮表,row_format=compressed并制定較小的page size。Page越小請求的I/O越少,特别是SSD。
Page size可以通過key_block_size指定。不同的page size 表示表必須在自己的ibd檔案裡面,必須啟動innodb_file_per_table。如果key_block_size越小,因為page越小,I/O效率提高。但是如果過分小,如果不能壓縮的單個page中,就需要額外的操作去重組page。
在buffer pool壓縮資料以小page儲存。Page size依據key_block_size,對于提取和更新,MySQL會配置設定16KB的非壓縮資料。然後在生産壓縮頁。可能需要加大buffer pool來儲存壓縮和非壓縮頁,盡管非壓縮頁會在記憶體不夠時被犧牲。
在建立壓縮表前,先要啟動innodb_file_per_table和innodb_file_format=Barracuda然後建立表或者修改,并指定row_format=compressed,key_block_size。
SET GLOBAL innodb_file_format=Barracuda;
CREATE TABLE t1
(c1 INT PRIMARY KEY)
ROW_FORMAT=COMPRESSED
KEY_BLOCK_SIZE=8;
1.若指定了row_format=commpressed可以忽略key_block_size,預設page是innodb_page_size的一半。
2.指定了key_block_size,可以忽略row_format=compressed,會自動啟動壓縮。
3.确定key_block_size的最好方法是,對同一個表按size不同配置設定建立壓縮,并且比較負荷。
4.key_block_size被認為是提示,如果是0就表示innodb_page_size的一般,key_block_size<=innodb_page_size,若innodb_page_size>key_block_size就會被忽略,并設定為innodb_page_size的一半。如果innodb_strict_mode=on則會報錯。
5.其他性能相關的看14.7.3 壓縮表調優
MySQL key_block_size可以1KB,2KB,4KB,8KB,16KB,但是不會影響壓縮本身的算法,隻是決定每個chunk的大小。
設定Key_block_size等于InnoDB page size就表示可能沒有太大的壓縮比率。但是對于TEXT,BLOB,varchar還是有用的,可以減少overflow page。
表上的所有索引被壓縮都使用相同的page size。由create table或者alter table指定。Create index中的row_format,key_block_size不是innodb表的屬性,如果指定會被忽略。
壓縮表的限制:
Innodb系統表空間不能使用表壓縮。壓縮隻能應用在整個表和索引上。不能用在指定行集上。
壓縮比率和資料有關,但是可以決定壓縮表的性能影響:
1.什麼表要壓縮。
2.使用多大的page size
3.runtime情況下如何調整buffer pool大小。
4.若系統執行了DML操作在壓縮表上,而資料是分布方式導緻高昂的壓縮操作失敗,可能需要額外的進階配置選項。
一般壓縮在讀多寫少的表上效果好。
關鍵決定壓縮效果好壞的是資料本身。決定是否使用壓縮表,需要測試,可以使用gzip對ibd檔案壓縮,簡單的評估壓縮比率。MySQL的壓縮比率比工具的壓縮比率少,MySQL隻能以key_block_size進行壓縮,并且系統資料不會被壓縮。而壓縮工具可以有更大的chunk,壓縮比率會更高。
另外一種方法是複制為壓縮的表,然後進行壓縮,看壓縮比率。
檢視在特定負荷下,壓縮是否是有效率的:
1.簡單的測試,在執行個體上隻有一個壓縮表,測試并檢視information_schema.innodb_cmp表。
2.若果要做精心的測試,運作information_schema.innodb_cmp_per_index表,因為表資訊收集開銷比較大,需要啟動innodb_cmp_per_index_enabled。
3.檢查成功壓縮的比率,對比innodb_cmp_per_index表和innodb_cmp表。
4.如果壓縮成功操作率很高,那麼比較适合做壓縮。
5.如果壓縮失敗比較好,應該調整innodb_compression_level,innodb_compression_failure_threshold_pct,innodb_compression_pad_pct_max選項。
決定是否在資料庫壓縮或者在應用程式壓縮,如果都壓縮隻會浪費cpu。
當啟動,MySQL表的壓縮是自動應用到所有的列和索引上。
在應用程式中壓縮,insert之前程式需要壓縮文本資料。可以減少負荷,但是會出現有的資料壓縮比率高,有的資料壓縮比率低。
在決定要壓縮什麼表的時候,工作負荷特點也是會影響性能的重要因素之一。若應用程式以讀為主,基本不需要重新組織和壓縮索引page。Delete相對高效,因為可以通過修改非壓縮資料表示資料已經被删除。
如果你的工作負荷是IO密集的,不是cpu密集,使用壓縮表可能可以提高性能。
壓縮試圖通過CPU壓縮,解壓,來減少I/O。尤其是在多使用者,多cpu環境下。Page在記憶體中被壓縮往往會保留非壓縮壓在記憶體中。LRU算法會試圖平和壓縮頁和非壓縮頁。
壓縮page大小設定,依賴于資料類型和分布,壓縮page size必須必最大的行大小大,不然會報錯。
Page太大會浪費空間,若果太小insert,update要花時間重新壓縮導緻b樹分頁頻繁,導緻檔案變更大,但是查詢效率很低。
通常,可以設定壓縮page 為8k,4K。
檢視整體程式性能,CPU,I/O和檔案大小可以很好的表示壓縮效率。要深入分析壓縮表性能,你需要監控information_schema中的表,這些表整體的反應了内部的記憶體使用和壓縮率。
Innodb_cmp表,根據page大小來收集資訊。在沒有其他壓縮表情況下,可以使用這個資料。
Innodb_cmp_per_index,對每個表和索引進行資訊收集。這些資訊對于診斷性能問題很有幫助。需要去啟動參數innodb_cmp_per_index_enabled才能啟動表資料的收集。
最關鍵的是考慮壓縮和解壓的次數。比較innodb_cmp_per_index在innodb_cmp中成功壓縮的比率,調整buffer pool,調整page size,或者不壓縮。
如果因為壓縮cpu上升,可以更新cpu,增加buffer pool,可以讓壓縮和非壓縮的頁都放在記憶體減少減壓操作。
大量的壓縮操作,說明寫入壓縮表操作頻繁,影響壓縮效率。如果成功壓縮操作 (COMPRESS_OPS_OK)在總操作(COMPRESS_OPS)比率高,表示系統執行良好。若比率低,考慮不要壓縮這個表或者增加頁大小,比率低說明MySQL重新組織,重新壓縮,分頁操作頻繁。如果壓縮失敗大于1%~2%考慮停止壓縮。
MySQL使用LZ77壓縮,是無損壓縮通常壓縮率在50%以上。InnoDB壓縮應用在使用者資料和索引中,很多情況下,索引占了40%~50%甚至更高的比率,是以差異是很明顯的。可以通過參數innodb_compression_level來平衡cpu和壓縮率。
Innodb所有資料都以b樹方式存儲,索引也是b樹,索引會包含索引key和一個指向聚集索引的指針。Btree的壓縮和overflow的壓縮不同,後面章節解釋。
因為連續的更新,b樹要特别對待,最小化分頁,最小化解壓重新壓縮。MySQL以非壓縮的方式,可以提高一些in-place update,比如delete-marked。
另外MySQL視圖避免不必要的解壓,重新壓縮。在每個btree page系統維護了一個未解壓的“modification log”來記錄page的修改。小的insert和update會被記錄在這個log中,沒必要去重構整個page。
當modification log空間不足,InnoDB解壓page,應用修改并重新壓縮page。如果重新壓縮失敗,btree分頁,這個操作會持續直到成功insert或者update。
為了避免頻繁出現壓縮錯誤在寫入密集負荷中,MySQL有時候會保留一些空閑空間,就是pge的padding空間。這樣modification log會執行的比較快。Page重新壓縮也有足夠的空間,不會分頁。
在繁忙的系統壓縮表插入頻繁,可以調整innodb_compression_failure_threshold_pct和innodb_compression_pad_pct_max。
通常MySQL要求page要包含2條記錄,對于壓縮表,要求在非壓縮頁上容納一行記錄。如果再innodb_strict_mode=on MySQL在create table,create index的時候檢查最大行大小,如果不能放入,會出現row too big的錯誤。
如果innodb_strict_mode=off,接下來的insert或者update試圖建立row的時候因為無法插入就會報錯。為了解決這個問題重新設定key_block_size,或者不要壓縮。
在InnoDB中BLOB,VARCHAR,TEXT可能儲存在overflow。Row_format=dynamic或者compressed,BLOB,VARCHAR,TEXT字段可能儲存在page外面,聚集索引儲存了20B的指針指向這些page。當行太長不能被儲存在同一個page中,MySQL會選擇一個最長的列儲存到off-page中.
如果row_format=dynamic或者compressed如果text,blob>=40個位元組會被in-line儲存。
如果是Antelope檔案格式,MySQL會儲存前768位元組,後面的20位元組指向後面的overflow page。
如果表是compressed格式的,所有的overflow page也會被壓縮。MySQL使用zlib壓縮算法壓縮一個資料項。壓縮的overflow頁包含非壓縮的頭和一個page checksum和連接配接到下一個overflow的連接配接。是以如果blob,varchar,text是重大的空間節約。Image資料一般都是被壓縮過的,再壓縮隻會浪費cpu。
使用16KB壓縮頁大小,也可以減少blob,varchar,text的IO消耗。
在壓縮的innodb表,壓縮頁是1KB,2KB,4KB,8KB。16KB不壓縮。為了最小化I/O和page解壓,buffer pool包含壓縮的page和未壓縮的page。為了空間MySQL會犧牲buffer pool中的非壓縮,或當有一段時間沒有通路後,會把壓縮寫入disk釋放記憶體。
MySQL使用自适應LRU算法來決定壓縮頁和非壓縮頁之間的平衡。目标是避免cpu密集的時候,花時間去解壓。Cpu空間的時候避免I/O。
當I/O忙,會犧牲非壓縮,釋放記憶體。
當cpu忙,會保留壓縮和非壓縮page。
在壓縮頁寫入資料檔案前page會被寫入到redo log,保證redo log了,crash之後依然可用。是以一些執行個體會變大,或者checkpoint會變頻繁,由壓縮頁被修改導緻重新組織和重新壓縮決定。
通常推薦在隻讀,或者讀多寫少的負荷下做壓縮。在SSD上使用壓縮,可以減少空間和IOps,即使在寫多的負荷下使用。
壓縮的配置:
1.innodb_compression_level,設定壓縮級别,越高,就可以放入越多的資料
2.innodb_compression_failure_threshold_pct,指定壓縮錯誤率的中止點,如果超過這個值,MySQL在配置設定新頁的時候保留一些空白空間,自動調整空閑比率。最大值由innodb_compression_pad_pct_max來決定。
3.innodb_compression_pad_pct_max,可以調整每個頁做大的保留白間。
Row_format=comressed或者key_block_size在create table或者alter table語句中,如果沒有啟動Barracuda檔案格式,會有用以下幾個錯誤。
Level
Code
Message
Warning
1478
InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
InnoDB: KEY_BLOCK_SIZE requires innodb_file_format=1
InnoDB: ignoring KEY_BLOCK_SIZE=4.
InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table.
InnoDB: assuming ROW_FORMAT=COMPACT.
預設這些警告,會導緻表建立但是不帶壓縮功能。當啟動了innodb_strict_mode就會報錯。
在“non-strict”條件下,mysqldump可以導入到不支援壓縮的資料庫。如果源資料庫中有壓縮表,那麼就會建立row_format-compact而不是阻止錯誤。當dumpfile導入到新資料庫,在原始庫上的表都會被重建。保證服務設定了适當的innodb_file_format或者innodb_file_per_table。
Key_block_size設定隻允許在row_format=compressed下使用,或者被忽略。
InnoDB: ignoring KEY_BLOCK_SIZE=n unless ROW_FORMAT=COMPRESSED.
如果設定了innodb_strict_mode就不會警告,會直接報錯,表不會被建立。
Create table和alter table選項
Option
Usage Notes
Description
ROW_FORMAT=REDUNDANT
Storage format used prior to MySQL 5.0.3
Less efficient than ROW_FORMAT=COMPACT; for backward compatibility
ROW_FORMAT=COMPACT
Default storage format since MySQL 5.0.3
Stores a prefix of 768 bytes of long column values in the clustered index page, with the remaining bytes stored in an overflow page
ROW_FORMAT=DYNAMIC
Available only withinnodb_file_format=Barracuda
Store values within the clustered index page if they fit; if not, stores only a 20-byte pointer to an overflow page (no prefix)
ROW_FORMAT=COMPRESSED
Compresses the table and indexes using zlib
KEY_BLOCK_SIZE=n
Specifies compressed page size of 1, 2, 4, 8 or 16 kilobytes; implies ROW_FORMAT=COMPRESSED
當innodb_strict_mode=off,會忽略設定,并生産警告,如果為on,會生産錯誤,不會被建立。
Syntax
Warning or Error Condition
Resulting ROW_FORMAT, as shown in SHOW TABLE STATUS
ROW_FORMAT=REDUNDANT
None
REDUNDANT
ROW_FORMAT=COMPACT
COMPACT
ROW_FORMAT=COMPRESSED orROW_FORMAT=DYNAMIC orKEY_BLOCK_SIZE is specified
Invalid KEY_BLOCK_SIZE is specified (not 1, 2, 4, 8 or 16)
KEY_BLOCK_SIZE is ignored
the requested row format, or COMPACT by default
ROW_FORMAT=COMPRESSED and valid KEY_BLOCK_SIZE are specified
None; KEY_BLOCK_SIZE specified is used
COMPRESSED
KEY_BLOCK_SIZE is specified withREDUNDANT, COMPACT or DYNAMICrow format
REDUNDANT, COMPACT orDYNAMIC
ROW_FORMAT is not one ofREDUNDANT, COMPACT, DYNAMIC orCOMPRESSED
Ignored if recognized by the MySQL parser. Otherwise, an error is issued.
COMPACT or N/A
在InnoDB中,新的檔案格式,就意味着新的特性。
Innodb_file_format選項在建立新的表的時候起作用。并且必須要啟動innodb_file_per_table。目前隻支援Antelope和Barracuda檔案格式。Innodb_file_format可以再配置檔案中設定,也可以通過set global設定。
向後相容性
新的InnoDB建立的表可能不會安全被上個版本的InnoDB讀寫。InnoDB 1.1提供了保證這些條件的機制,來保證資料檔案和innodb版本的相容性,這個機制可以使用新版本提醒,有要保留這些選項,并防止不相容特性的使用。
若改版本InnoDB支援某版本的檔案格式,那麼就可以讀寫任意這個版本之前版本的表。特定的檔案格式會限制一些特性,反過來若表空間使用了目前不支援的檔案格式,那麼就無法通路。隻能降級innodb表空間到之前的版本,然後複制到新的表。
最簡單決定檔案格式的方法是使用show table status指令或者查詢表tables的row_format字段。
内部細節
每個innodb表空間都有一個檔案格式标記,系統表空間是hightest。建立壓縮表和dynamic會更新ibd檔案頭,在innodb資料字典中标記barracuda檔案格式。InnoDB會根據這個标記來檢查相容性。
Ib_file集合的定義
Ib_file集合包含:
1.系統表空間一個或者多個ibdata檔案,包含了系統内部資訊。
2.多個簡單表空間,*.ibd檔案
3.InnoDB日志檔案,ib_logfile0,ib_logfile1。Redo日志檔案。
Ib-file集合,不包含frm檔案。Frm郵件是由mysql建立的。
為了防止在打開ib-file set的時候出現crash,就會檢查是否完全支援ib-file的檔案格式。若目前軟體的格式太新,在恢複的階段,會照成驗證的資料破壞,是以啟動檢查檔案格式可以防止之後的一些列問題。
從innodb 1.0.1版本開始系統表空間會記錄,把使用過的最高的檔案格式作為ib-file set的一部分。檔案格式檢查有參數innodb_file_format_check控制。如果當參數為on,并且mysql支援版本低于檔案的版本。
InnoDB: Error: the system tablespace is in a
file format that this version doesn't support
有些情況下,可能要讀取太新的檔案,如果innodb_file_format_check=off。Innodb打開資料庫的時候會警告:
InnoDB: Warning: the system tablespace is in a
如果允許怎麼運作,是很危險的。
參數innodb_file_format_check,影響資料庫被打開的時候,innodb_file_format隻決定在新表是否可以以某格式建立,并不影響是否可以打開資料庫。
若有更高的格式的表被建立或者已經存在可讀寫的表的格式高于目前軟體。系統表不會被更新,但是會啟動表級别的相容性檢查。
當表被通路,InnoDB會檢查檔案格式。防止當表使用太新的資料結構時,crash,損壞。隻要release支援可以讀寫任意檔案格式的表。指定innodb_file_format會阻止建立一個指定特定檔案格式的新表,甚至是release是支援的。這樣設定會阻止向後相容性,但是不會妨礙對支援格式的通路。
InnoDB在檔案打開的會後檢查檔案格式相容性。若現在InnoDB把呢吧不支援InnoDB檔案中的标記。
ERROR 1146 (42S02): Table 'test.t1' doesn't exist
也會寫入error log
InnoDB: table test/t1: unknown table type 33
盡管innodb設定了參數innodb_file_format_check,允許打開不支援檔案格式,表級别檢查還是會被應用。
Innodb_file_format隻影響新增的表,若你新增了一個表,表被标記使用最早的檔案格式。比如啟動了barracuda并且建立了新表,沒有使用dynamic,compressed。那麼表會被标記為Antelope。
如果得知表或者表空間,可以使用表tables,或者show create table獲得檔案格式。若沒有使用comressed,dynamic。就會使用Antelope的檔案格式,row_format為redundant或者compact。
InnoDB有2個檔案格式,Antelope,Barracuda,4個不同的行格式。檔案和行格式,以32bit解除安裝檔案的54位置。可以使用od -t x1 -j 54 -N 4 tablename.ibd.檢視。
表空間flag錢10個bit:
0bit:0表示Antelope,1-5bit為0,1表示Barracuda,1-5為1.
1-4bit:表示壓縮檔案的page size,1=1k,2-2k,3=4k,4=8k。
5bit:antelope=0,Barracuda=1.
6-9bit:4位元組數值,0=16K,3=4K,4=8K,5=16K
10bit:表空間位置,0=預設,1=使用了data directory子句。
Table flag要使用語句檢視中的flag:
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
前7bit:
0bit:0=Redundant 行格式,1-5就為0。1=compact 行格式。
1-4bit:4bit數值,表示壓縮頁,1=1k,2-2k,3=4k,4=8k。
5bit:0:Antelope,1=Barracuda,如果為1,0bit也要為1
6bit: 表空間位置,0=預設,1=使用了data directory子句。
最簡單的方法:
ALTER TABLE t ROW_FORMAT=format_name;
行和相關列的存儲會影響查詢和DML性能。更多的行放到一個page裡面,查詢的時候會更快,記憶體更好,I/O也會變少。InnoDB中資料被放入page中,page通過構成B樹結構來儲存。一行的資料都被儲存在page裡面,但是變長字段是例外。因為太長會溢出,是以這些隻被儲存在overflow page上。有個link連接配接到這些page。
語句如下:
CREATE TABLE t1 (f1 int unsigned) ROW_FORMAT=DYNAMIC ENGINE=INNODB;
Dynamic,compressed隻有在檔案格式為Barracuda才能使用。Barracuda也支援compact,redundant格式。
使用Dynamic,compressed長列會被儲存在off-page上。聚集索引上會保留20byte的執行。
是否使用off-page,取決于page大小和行大小。當行太長,innodb會吧最長的列作為溢出直接放到溢出page。Text,blob如果小于40位元組都會in-line儲存。
如果行可以存放在page中,Dynamic行模式也是很有效的。Dynamic為有長資料儲存在off-page設計的。是以效率比老的行模式好。
Compressed行格式off page的存儲和dynamic類似。差別是compressed對表和索引進行了壓縮。
早前的InnoDB使用者2個行格式。對于溢出,InnoDB會把錢768位元組儲存在page上,後面的儲存在溢出頁上。對于少于768的列會被儲存在page内,對于有很多blob的列會顯得太滿。
在linux和windows平台,innodb使用OS自帶的來支援原生異步I/O。在其他平台使用模拟的異步I/O。
預讀
如果innodb可以決定,資料被馬上需要的可能性很高,就會執行預讀把輸入讀入記憶體,預讀有2種方式:
1.線性預讀,當innodb發現通路方式是順序的,發起額外的page讀。
2.随機預讀,innodb發現資料可能要全部處理,會持續的讀。
雙寫buffer
InnoDB使用新檔案重新整理技術,涉及到雙寫buffer。增加了crash的安全性和提高性能減少fsync()。
在寫入資料檔案之前,會先寫入到雙寫buffer。寫入到雙寫buffer之後innodb把這些寫入到資料檔案中。
為了避免index和表都儲存在系統表空間,使用參數innodb_file_per_table,每個新的建立表有獨立的表空間檔案,這樣可以減少檔案碎片。當表被截斷可以傳回給系統,而不是系統表空間。
page,extents,segments和tablespace
tablespace由page組成innodb_page_size來制定page的大小。組成1MB的extents,表空間中的檔案在innodb中被稱為segment。一開始innodb配置設定32page,之後會配置設定整個extents。innodb可以一次性配置設定4個extents。innodb會為每個索引配置設定2個segments,一個非葉子,一個葉子。葉子節點在磁盤中連續,順序I/O操作順序會更好。因為葉子節點包含了表的實際資料。
表空間中的有些page包含其他page的bitmap。是以有些extents在表空間中,不能被整體配置設定。隻能page單獨配置設定。
當使用show table status檢視表空間中可用的空閑空間。會發現有些extents是空閑的。innodb為了清理和啟動目的而保留的一些空間。
空閑出來的空間是可以讓别的使用者使用依賴于是否釋放了幾個page還是extentds。drop table或者delete所有行空間釋放給使用者,但是實體删除操作在事務復原和一緻性讀不需要的時候執行。
page如何關聯表記錄
行最大記錄為8000位元組。longblob和longtext必須少于4GB,所有的行長度,包含blob和text必須少于4gb。
若行少于一半的page,則都有放在page中,若超過了一半page會選擇變成放入overflow,直到可以放入page的一半。
檢查點如何處理程序
innodb實作了一個模糊檢查點的機制。innodb會重新整理小批量的髒資料,但是重新整理時會中斷語句執行。
在crash恢複,innodb會檢視寫入到log檔案的檢查點标記。檢查點标記表示在标記之前的資料都被寫入到了磁盤中。innodb應用之後的log即可。
随機插入和删除會造成碎片,碎片表示空隙。碎片的症狀是會花比更多的空間。另外一個症狀是掃描會花更多的時間。
為了整理碎片要定期執行空的alter table。
ALTER TABLE tbl_name ENGINE=INNODB
alter table tbl_name engine=innodb和alter table tbl_name force都使用online DDL(ALGORITHM=COPY)。
表有自己的表空間時,truncate table空間會被os回收。truncate table表和其他表不能有外鍵限制。
當表被truncate,會删除并且重建表,生成ibd檔案,并且空閑空間傳回給OS。
Online DDL有一些好處:
1.提高了繁忙環境的相應和可用性,避免在繁忙環境下為了一個新的索引停止很長時間。
2.可以讓你在性能和并發性上平衡。
3.可以in-place完成,不需要建立一個新的表。
曆史上,沒有online操作,很多alter table操作會建立一個新表來代替老的表。MySQL 5.5,MySQL 5.1之後 innodb plugin create table和drop table來避免表複制行為。叫做快速索引建立。MySQL 5.6之後所有的alter table都可以避免表複制。
新的機制通過先導入資料再建立索引方式來提高速度。雖然在文法上沒有改變,但是一些特性會影響性能,空間使用和操作的語義。
Online DDL增強了很多DDL操作,表複制,DML Blocked。
Secondary Index
建立索引,<code>CREATE INDEX</code> <code>name</code> <code>ON</code> <code>table</code> <code>(</code><code>col_list</code><code>)</code> or <code>ALTER TABLE</code> <code>table</code> <code>ADD INDEX</code><code>name</code> <code>(</code><code>col_list</code><code>)</code>.
删除索引,<code>DROP INDEX</code> <code>name</code> <code>ON</code> <code>table</code><code>;</code> or <code>ALTER TABLE</code> <code>table</code> <code>DROP INDEX</code> <code>name</code>
MySQL 5.6版本之後,索引被建立或删除時,可以讓DML繼續使用。
類屬性
設定預設值,<code>ALTER TABLE</code> <code>tbl</code> <code>ALTER COLUMN</code> <code>col</code> <code>SET DEFAULT</code> <code>literal</code> or <code>ALTER TABLE</code> <code>tbl</code> <code>ALTER COLUMN</code> <code>col</code> <code>DROP DEFAULT</code>
修改自增下一個值, ALTER TABLE <code>table</code> AUTO_INCREMENT=<code>next_value</code>;
重命名列, <code>ALTER TABLE</code> <code>tbl</code> <code>CHANGE</code> <code>old_col_name</code> <code>new_col_name</code> <code>datatype</code>
外鍵
外鍵建立和删除
使用foreign_key_checks啟動主鍵和外鍵。
若不知道限制名,可以使用語句檢視:
也可以在一個語句内删除外鍵和索引
如果已經存在altered表中,應用DDL操作有額外的限制。
1.在這些子表上線上DDL不允許并發DML
2.alter table子表會等待另外一個事務送出。如果在父表上的修改會影響到子表,比如設定了cascade,或者set null。
若一個表是父表,若DML帶有on update,on delete那麼就要等alter table 完成。
注意ALGORITHM=COPY
alter table使用algorithm=copy,并發DML就不能使用。并發查詢還是允許。表複制操作在lock=shared下運作,也可以在lock=exculusive下。
并發DML和表複制
有些DML操作允許并發DML但是還是要執行表複制。以下操作比MySQL 5.5快:
1.添加,删除,重排列
2.增加,删除主鍵
3.修改row_format和key_block_size
4.修改列是否為空
5.optimize table
6.force選項來建立表
7.alter table engine=innodb來重建表。
盡管 online DDL很有效,但是還是要建立一個穩定的表結構。主要的例外是secondary index,對于大表,通常是最後建比較有效。不管create table,index,alter table什麼順序都可以使用show create table來獲得目前表結構。
Online DDL有幾個方面的提升:
1.DDL操作時,也可以查詢和DML,可用性更高。
2.對于in-place操作,重建表時,避免disk I/O,CPU。
3.對于in-place操作,讀入的資料更少,讀入buffer pool的資料比複制所有的資料少,避免臨時的性能問題。
如果online操作需要臨時檔案,InnoDB建立在零食檔案夾中,而不是在資料目錄中。
Online DDL鎖操作
在DDL操作時,表可能會被鎖,取決于内部操作過程和lock子句。預設mysql是使用最小的鎖定。如使用的鎖不支援就會報錯。
1.對于DDL操作,使用lock=none,查詢和并發DML都可以被允許。如果DDL不允許lock=none,alter table就會報錯。
2.對于DDL操作,使用lock=shared,任何寫入都會被block,若不支援鎖定類型就會報錯。
3.對于DDL操作,使用lock=default,mysql使用最小的鎖級别。
4.對于DDL操作,使用lock=exclusive,查詢和DML都會被block。
Online DDL語句都等innodb表上的事務運作完成後再運作,因為DDL在準備時要申請X鎖。online DDL操作可能要比老的DDL操作要慢。
In-Place vs Table-Copy DDL
online ddl的性能受到in-place,copying和rebuilding整個表影響很大。in-place使用在secondary上,不能使用在primary,primary上依然隻能使用copying data。
當使用子句ALGORITHM=INPLACE,盡管使用的是copy data,但是性能還是要比ALGOTITHM=COPY好:
1.沒有undo或者徐昂管的redo生成。
2.secondary可以預先排序,是以可以按順序被導入
3.沒有使用change buffer,因為沒有随機寫入到secondary索引。
簡單的識别是否使用了inplace或者copy就是看相應行數,如果響應為0行,說明inplace:
1.修改列的預設值,沒有響應行數
2.增加索引(雖然然有時間花費,但是沒有響應行)
3.修改資料類型(時間消耗,并且重建了表)
在處理大表之前,最好先進行測試:
1.克隆表結構
2.導入少量資料
3.執行DDL操作
4.檢查響應行數,看是否inplace
可以通過ALGORITHM和lock來控制online DDL的不同方面。Lock是并發性控制,ALGORITHM是和老的copy table最主要的差別之一,如:
1.避免了不小心,讓表處于不可讀,寫狀态,可以通過alter table lock=none來避免。
2.可以使用ALGORITHM=inplace和ALGORITHM=copy來比較性能。
3.使用ALGORITHM=inplace,如果語句不能用inplace方式,會立刻停止。
DDL語句,可以把多個DDL操作放在一起,因為每個alter table都會涉及複制和重建表,可以一次性全部完成。
如果可以使用inplace,就可以把多個DDL分解成多個語句
分解為:
有些情況下,還可以使用多alter table:
1.如果操作需要特定的順序
2.如果操作使用相同的lock,并且要一起成功或者失敗。
3.操作不能以inplace方式執行,任然需要複制,重建表。
4.或者指定了,ALGORITHM=COPY或者old_alter_table=1
任何alter table操作都有以下幾個方面:
1.是否會修改表的實體表示,或者隻修改中繼資料,不會涉及表本身。
2.資料量是否會變化
3.修改的表是否涉及,聚集索引,secondary索引或者兩則
4.是否和其他表有外鍵關系
5.是否分區,如果是分區表,會被調到低級别操作涉及到多個表,這些操作要是用Online DDL需要特定的規則。
6.表是否一定複制,是否表可以被以inplace方式重組。
7.表是否包含自增列
8.需要的鎖級别。
Online DDL的錯誤條件
以下是online ddl報錯的主要原因:
1.如果指定了鎖級别過低,DDL操作不支援。
2.等到鎖曹氏
3.tmpdir檔案系統超出了空間
4.alter table太長導緻超出innodb_online_alter_log_max_size。
5.如果并發DML修改表,在之前的定義被允許,但是在新的不被允許。
Online DDL在有沒有啟動innodb_file_per_tale無關。innodb中有2個索引,聚集索引和secondary索引。聚集索引是表本身,是以所有的修改都會導緻,copy。secondary索引是表的副本,也隻是一部分資料,不需要copy。
删除secondary索引比較簡單,隻要修改中繼資料即可。增加索引,innodb會掃描并使用buffer和臨時表來排序。這樣比随機插入到一個建好的索引效率高。因為當page滿了會産生分頁。
Primary Key和Secondary Key索引
MySQL服務和InnoDB會儲存他們的中繼資料。MySQL服務會把資訊儲存在frm檔案中。InnoDB把資料字典儲存在系統表空間中。如果DDL操作crash中斷,造成2邊資料不一緻,會出現啟動問題,表不能被通路。
雖然不會丢失資料,但是恢複方式和b樹索引不同。如果在建立secondary索引crash。MySQL會删除建立的索引,需要重新建立。
建立聚集索引時,因為資料從一個表複制到另外一個表,crash會比較複雜。MySQL在建立時先複制資料到臨時表,一旦完成,新表替換老的表。
若在建立新聚集索引,系統crash,沒有資料丢失但是使用臨時表來恢複。因為很少出現是以手冊不提供這樣的場景。
除了alter table分區語句, online ddl分區表和普通表類似。alter table分區子句内部api和非分區表不同隻能使用ALGORITHN=DEFAULT和lock=default。
如果在alter table上使用alter table分區子句,使用alter table copy算法分區表會被重新分區。也就是說分區表以新的結構被重建。
若不使用alter table修改分區表分區,alter table會在每個分區上使用inplace算法。使用inplace的alter table選項,分區越多會需要越多的資源。
盡管分區表和非分區表使用的alter table api不同,MySQL依然視圖最小化資料複制和鎖定:
1.add partition和drop partition在range或者list分區上不會複制資料。
2.truncate partition不會複制資料。
3.在range,list上進行add partition和coalesce partition,可以和查詢并發。
4. REORGANIZE PARTITION, REBUILD PARTITION,ADD PARTITION 或者 COALESCE PARTITION在linear hash或者list上,允許并發查詢。
當執行DDL有一下限制:
1.當執行online ddl時,複制表,寫入臨時目錄,臨時表要足夠大。
2.alter table drop inxex和add index子句,2就會使用表複制,而不是快速索引建立。
3.在臨時表上建立索引,使用表複制。
4.在删除被外鍵使用的索引會報錯。
5.不能在on…cascade或者on…set null語句下使用alter table lock=none
6.在online DDL時不管使用什麼lock子句,在開始和結束都會請求X鎖。是以要等待上個事務完成。
7.當執行online alter table,執行alter table的會啟動一個online log,用于記錄其他會話的DML操作。當執行DML操作就有可能會出現重複鍵錯誤。可能錯誤是暫時的,之後在online log中被恢複。
8.InnoDB表的OPTIMIZE TABLE被映射到alter table操作,重建表并更新索引,釋放沒用的空間。
9.在5.6版本之前,innodb不支援alter table ALGORITHM=INPLACE。
預讀是I/O請求異步的擷取多個page。InnoDB有2個預讀算法來提高I/O性能:
Liner
線性預讀根據buffer pool中的page,預測需要什麼page。通過參數調整什麼時候執行預讀,讀取多少page,使用innodb_read_ahead_threshold就可以。
innodb_read_ahead_threshold值越大越不會觸發。
Random
若buffer pool找打了13個page來自同一個extent,innodb會啟動異步I/O擷取其他page。由innodb_randmon_read_ahead參數控制。
SHOW ENGINE ENNODB STATUS顯示統計資訊來評估預讀算法的效果。innodb_buffer_pool_read_ahead通過預讀讀入的page,innodb_buffer+pool_ahead_evicted,通過預讀讀入但是被犧牲的page。
當髒頁超過innodb_max_dirty_page_pct時之後會啟動重新整理程序。innodb使用算法根據目前redo log生産和目前的重新整理來生産目前重新整理率。
innodb使用log檔案,在重用log前,要把相關的髒頁寫入到資料檔案中,這就是sharp checkpoint,當log file中所有可用空間都用完了,也會發生sharp checkpoint,即使innodb_max_dirty_page_pct沒到達也會發生。
innodb通過啟發式的算法,避免這種情況發生。通過評估dirty和生成的redo來決定flush多少髒頁。
因為自适應flush會影響I/O,innodb_adaptive_flushing可以開關自适應flush,預設為true。
InnoDB的LRU算法目的是讓hot資料盡量儲存在記憶體中。新的page被讀入預設插入到LRU清單距離尾部3/8處。若再次被提到隊列前面,如果不再被通路,就不放到隊列前面。可以通過參數innodb_old_block_pct來調整插入到LRU清單的點。預設是37也就是3/8處。取值範圍是5-95。
為了避免預讀有類似問題,影響buffer pool配置innodb_old_blocks_time判斷第一次通路後放入清單頭的倒計時。
innodb_old_blocks_pct和innodb_old_blocks_time可以在配置檔案,啟動參數,也可以set global設定。
通過show engine innodb status指令檢視:
old database pages表示LRU 清單 old段的page個數
pages made young和not young,表示old段的page被标記為young和沒有被标記的個數。
youngs/s和non-youngs/s,表示表示被youngs的速度。
young-making rate和not提供了一樣的速率,但是是整個buffer pool的不是old段。
每秒的速度是通過上次螢幕和這次螢幕的取值的內插補點。
這些選項根據硬體配置關系較大,是以在設定前要先進行壓力測試。
在混合負荷下,oltp為主,和定期的報表查詢,可以使用innodb_old_blocks_time參數。
當讀取的表放不進buffer pool可以通過設定innodb_old_blocks_pct,如果為5 表示隻有5%的buffer pool别使用,不影響其他的buffer pool。
若掃描表的表,innodb_old_blocks_pct可以預設或者更高,對性能影響較小。
innodb_old_blocks_time更難預測,因為和負荷類型關系密切。
對于有幾個G的buffer pool可以吧buffer pool分為多個執行個體提高并發減少沖突。可以使用innodb_buffer_pool_instances來配置。使用innodb_buffer_pool_size來配置buffer大小。
當buffer pool變大,很多資料可以存放在buffer pool中,但是多個線程同時通路buffer pool可能會出現瓶頸。可以使用多個buffer pool來最小化争用。每個page被配置設定到哪個buffer pool是随機的。每個buffer pool都有自己的信号量。
Innodb_buffer_pool_instances取值1~64,隻有當innodb_buffer_pool_size>1GB,上面的參數才有用。指定的總大小會被分到所有的buffer pool。
為了避免重新開機後長時間的warm up,你可以再服務關閉的時候儲存innodb buffer pool狀态,在啟動的時候,恢複buffer pool狀态。
一般重新開機之後,warm up是逐漸增加的,把之前的page加入到buffer pool。Preload可以再關閉之前的buffer pool加載到記憶體。而不需要DML來warmup。
背景專門有個線程來處理buffer pool dump和load。壓縮表上的page,以壓縮方式被加載到buffer pool。
儲存buffer pool 狀态
在關閉服務前,儲存buffer pool狀态
SET GLOBAL innodb_buffer_pool_dump_at_shutdown=ON;
在服務運作時,儲存buffer pool狀态
SET GLOBAL innodb_buffer_pool_dump_now=ON;
恢複buffer pool狀态
在恢複時,load buffer pool狀态
mysqld --innodb_buffer_pool_load_at_startup=ON;
在服務運作時,恢複buffer pool狀态
SET GLOBAL innodb_buffer_pool_load_now=ON;
檢視buffer pool dump進度
顯示Save進度
SHOW STATUS LIKE 'Innodb_buffer_pool_dump_status';
SELECT variable_value FROM information_schema.global_status WHERE
variable_name = 'INNODB_BUFFER_POOL_DUMP_STATUS';
如果沒有運作,顯示not started,如果已經完成顯示 completed at 150928 17:27:51,還在處理,顯示Dumping buffer pool 5/7, page 237/2873。
取消buffer pool load
SET GLOBAL innodb_buffer_pool_load_abort=ON;
參數innodb_flush_neighbors和innodb_lru_scan_depth可以調整innodb buffer pool的重新整理。
innodb_flush_neighbors:重新整理innodb page是否把同一個extent的也重新整理。
innodb_lru_scan_depth:掃描深度,若I/O有餘可以放大。
對于DML活躍的若不夠聚合重新整理操作會被拉開,造成高昂的記憶體消耗,如果太激進會導緻I/O能力耗光。最好的辦法是依賴工作負荷,資料通路方式和存儲來配置。
Innodb_adaptive_flushing,innodb_io_capacity和innodb_max_dirty_pages_pct 受限于:
innodb_adaptive_flushing_lwm,innodb_io_capacity_max ,innodb_max_dirty_pages_pct_lwm:
1.InnoDB自适應重新整理,并不适用于所有case,可能在redo log在filling up危險時又好處。Innodb_adptive_flusing_lwm表示一個redo log能力的低水位百分比,當達到閥值,innodb可以在沒有指定innodb_adaptive_flushing的情況下啟動flush。
2.若flush活動,被落的很多,innodb會比innodb_io_capacity_max更加積極的進行重新整理。Innodb_io_capacity_max表示I/O能力的上限,為了不讓I/O丢被耗光。
3.為了讓dirty page不超過innodb_max_dirty_pages_pct,innodb會重新整理buffer pool中的資料。預設參數值為75。
Innodb_max_dirty_pages_pct,建立起重新整理活動的目标。
Innodb_max_dirty_pages_pct_lwm選項指定低水位表示髒頁的百分比,來控制髒頁比率防止到達閥值innodb_max_dirty_pages_pct。
很多這些選項适用于長時間寫入并幾乎不會沒有減少負荷的時間,讓寫入磁盤跟上。
Innodb_flushing_avg_loops表示之前被計算重新整理狀态的快照,控制了自适應flush如何快速的反應前台負荷變化。Innodb_flushing_avg_loops值越大,儲存快照的時間越長,自适應重新整理響應越慢。值大,也會減少前背景工作的回報,設定的很高但是要保證innodb redo log不能到達75%,并且根據負荷合理設定innodb_max_dirty_pages_pct。
系統負荷基本不變,大innodb_log_file_size和small spike沒有到達redo log的75%空間使用,可以把innodb_flushing_avg_loops設定的稍微高一點,減慢flush。對于極端的情況或者空間不夠,可以考慮設定的小一點,避免redo log超過75%,更上負荷。
InnoDB多線程通路共享資料,innodb同步使用自己實作的mutex和read/write lock。在很多平台,有很多更高效的方式來實作read/write lock。原子操作通常用來同步多個線程的行為比pthread更有效。每個操作擷取和釋放鎖需要的指令更少。在通路沖突時浪費的時間更少,也就是說在多核平台上擴充性更好。
Innodb實作的mutex,read/write lock使用gcc自帶的原子記憶體通路而不是pthread。特别是innodb通過gcc 4.1.2編譯,使用gcc自帶的原子通路來代替pthread_mutex_t。
這些修改提高了innodb在多核系統中的擴充性。對于原子記憶體通路不可用的,innodb會使用傳統的pthreads方法來代替。
在啟動mysql,innodb會寫一個消息到日志檔案表示原子記憶體通路是否被用于mutex,read/write lock。另外compare-and-swap操作可以被用線上程表示,然後innodb同時也可以使用read-write lock。
在innodb被開發,記憶體配置設定由os和runtime library提供。如果innodb在mem子系統自己實作記憶體配置設定,配置設定器由一個mutex決定,可能會變成瓶頸。Innodb也對系統配置設定器最了分裝,像mutex一樣。
現在多核系統廣泛使用,OS也成熟,OS提供的記憶體配置設定頁有提升,比之前的更好,擴充性也更好。高效的記憶體配置設定器如Hoard, libumem, mtmalloc, ptmalloc, tbbmalloc, 和TCMalloc。對于跟多workload,記憶體配置設定釋放頻繁,使用高調整的配置設定器,比使用innodb的配置設定器更好。可以通過innodb_use_sys_malloc來決定使用自己的配置設定器或者OS的,1使用OS的配置設定器,0,使用自己的配置設定器。
當innodb記憶體配置設定器禁用了,innodb會忽略參數innodb_additional_mem_pool_size的配置,innodb使用額外的記憶體池,保證安全配置設定不會被退回到系統記憶體配置設定器。當innodb記憶體配置設定禁用,所有配置設定都由系統記憶體配置設定器完成。
當使用系統備份配置設定器(innodb_use_sys_malloc=on),因為innodb不能根治所有的記憶體使用。在show engine innodb status指令的BUFFER POOL AND MEMEORY段輸出隻有total memory allocated的統計。
當insert,update,delete操作在表上執行。Innodb有一個insert buffer當page不在記憶體中會緩存secondary index的修改,避免不必要的I/O操作。當被load到buffer pool就會和insert buffer進行合并。Innodb主線程在空間或者shutdown的時候會meger緩存的修改。
Insert buffer是buffer pool的一部分,會占用一些記憶體。如果workset幾乎要占用所有記憶體,取消insert buffer可能會更好。
Innodb_change_buffering用來控制insert buffer,取值如下:
All:預設值,buffer insert,delete-marking和purges
None:不buffer任何操作
Insert:buffer insert操作
Delete:buffer delete-marking操作
Changes:buffer insert和delete-marking
Purges:buffer 背景清理操作。
可以設定的my.ini裡面,也可以使用set global設定。
Innodb使用os線程來處理使用者事務,現在的os和伺服器,有多個核,上下文切換高效,很多工作在沒有并發線程限制下運作的很好。
Innodb會使用很多技術限制osthread并發執行數量,進而最小化上下文切換。當innodb接到使用者會話的請求,若并發線程的數量被限制,那麼新的請求會sleep,請求也不會sleep後被排程而是進去了先進先出的隊列。
通過innodb_thread_concurrency來限制并發線程,在innodb_thread_sleep_delay在進入隊列之前sleep的微秒。
MySQL 5.6.3之後設定innodb_adaptive_max_sleep_delay可以自适應調節sleep,是innodb_thread_sleep_delay的最高值。
Innodb_thread_concurrency=0表示并發線程沒有限制。隻有當并發線程數被限制的時候,才會sleep。如果不限制innodb_thread_sleep_delay被忽略。
當有線程限制時,innodb通過允許多個請求進入一個正在執行的會話,來減少上下文切換,不需要去觀察是否超出innodb_thread_concurrency。因為SQL語句包含了多個行操作,innodb會配置設定tickets允許線程重複被調用。
當SQL開始被運作,沒有tickets會看innodb_thread_concurrency獲得進去innodb的權力,并配置設定tickets。當tickets被用完會就檢視innodb_thread_concurrency獲得ticket,配置設定的tickets個數由innodb_concurrency_tickets決定。
InnoDB使用一些背景線程來為不同的I/O服務。使用innodb_read_io_threads和innodb_write_io_threads來配置讀寫的線程個數。這些參數的預設值為4,範圍在1-64。
這個目的是為了讓innodb在高端system上有更好的擴充性。每個背景線程可以控制256個堵塞I/O請求。大多數背景I/O的來源是預讀。Innodb視圖平衡輸入的負荷,很多背景線程都是共享任務的。Innodb也試圖把對同一個extent的讀放到同一個線程上。如果再高端的I/O子系統上看到大于64*innodb_read_io_threads的堵塞讀請求,在show engine innodb status上,可以增加innodb_read_io_threads。
曆史上InnoDB和其他資料庫一樣,在commit之前先要flush redo log。Innodb使用group commit,避免每個commit做一次flush。使用分組送出,innodb使用一個寫入對多個使用者事務進行送出,可提高吞吐量。
在MySQL 5.1之後被取消了。
分組送出功能,在innodb内不是使用二階段送出協定的,重新使用是為了保證binlog和
中的順序和以前一樣。當啟動了binlog,隻有當sync_binlog=0時,才能使用分組送出。
InnoDB主線程執行各種背景任務,大多數和I/O有關:1.flush髒頁,2.把insert buffer寫入到對應的index。
主線程試圖以新的方式執行這任務,并不影響其他正常工作。主線程嘗試評估I/O帶寬可用,在空閑時執行。
參數innodb_io_capacity表示innodb可用的I/O,這個參數表示每秒的I/O操作。主線程根據innodb_io_capacity評估可用的帶寬。
Innodb_io_capacity設定也限制所有的buffer pool執行個體。當髒資料重新整理,buffer pool會均分innodb_io_capacity。
在MySQL5.6.5和更高版本,這些IO操作被移動到了背景其他線程,這些值由innodb_purge_threads控制。
Innodb内部同步通常會使用自旋鎖,在等待的時候,innodb運作語段小的循環指令,避免重新排程。若自旋運作的太多會浪費資源,而造成失誤吞吐量下降。大多數現代處理器都實作了PAUSE指令在自旋上的使用。這樣處理器可以更加高效。
Innodb使用PAUSE指令可以增加CPU密集操作的性能。
很多innodb mutexes和rw-lock被儲存很短的是時間,多和系統,一個線程在sleep之前,連續的檢查mutex和rw-lock可能會更加有效。若mutex或者rw-lock在輪詢變可用,thread可以再同一個時間片上馬上運作。如果太頻繁的輪詢會導緻cache ping pong。Innodb最小化這個問題是,在輪詢之間等待一個随機事件。
通過參數innodb_spin_wait_delay輪詢之間的最大延遲,延遲的時間由編譯器和目标處理器決定。對于所有的cores共享一個cache可以減少延遲,或者設定innodb_spin_wait_delay=0限制繁忙循環在同時進行。
預設innodb_spin_wait_delay=6,可以設定在my.cnf或者set global。
從InnoDB 1.1開始,可以profile整個innodb操作,這種tuning是為了專家級使用者。DBA也可以使用這個功能做容量計劃,看是典型的workload是否有性能瓶頸問題。來判斷是否可以通過增加一些系統能力來提高性能。具體檢視22章
使用這個特性需要檢查:
2.必須熟悉如何使用performance schema特性
a.mutex在mutex_instances表
b.rw-lock在rwlock_instances表
c.檔案io操作,file_instances,file_summary_by_event_name和 file_summy_by_instance表
d.線程在PROCESSLIST表。
4.在性能測試的時候檢查,events_waits_current,events_waits_history_long表中的資料。
從innodb 1.1開始并發事務有極大的擴充,删除了之前innodb rollback segment的瓶頸限制。
現在從一個rollback segment分成128個segment每個都支援1023個事務讀寫。總共可以适應128K個并發事務。
每個事務都會被分到一個rollback segment。使用innodb_rollback_segment來配置rollback segment個數。
清理操作由innodb獨立自動運作的一個或者多個線程執行,而不是master thread的一部分。可以使用innodb_purge_threads配置線程個數。若DML比較集中就設定的小一點,這樣就不會和其他通路争用資源。若比較分散就設定的大一點。
另外一個相關的參數innodb_purge_batch_size預設為20,最大為5000
如果是隻讀事務,可以避免啟動事務ID的一些相關開銷。事務ID隻有在寫事務,或者select for update才會被需要。
InnoDB如何識别隻讀事務:
1.以start transaction read only啟動的事務。
2.自動送出事務非鎖定select,沒有for update或者lock in shared mode。是以讀密集的應用,可以把一組查詢放在start transaction read only和commit内。
CRC32 checksum算法,在mysql5.6.3加入,一次掃描32bits,通過優化隻需要掃描8bit。可以使用innodb_checksum_algorithm=crc32來啟動。
當crc32算法啟動,一旦被使用crc32算法寫入,以前的版本就無法讀取。當啟動新的mysql執行個體。并且innodb資料使用crc32算法建立。可以使用strict_crc32比crc32快,因為不需要向後相容。
從MySQL 5.6.3可以建立InnoDB undo log可以存放在獨立表空間中。Undo log也就是rollback segment。有幾個相關的配置參數:
1.innodb_undo_tablesspaces
2.innodb_undo_directory
3.innodb_rollback_segment,變成了innodb_undo_logs,字首為了相容而存在。
注意點
1.決定使用高速存儲存放undo logs,使用innodb_undo_directory指定路徑。
2.決定innodb_undo_logs的非0值,一開始可以使用較小的,之後在放大。
3.innodb_undo_tablespaces非0隻,有innodb_undo_logs個數的undo log被建立在制定的獨立表空間中。
4.建立新的MySQL執行個體,把這些值寫到配置檔案上
5.測試I/O性能。
6.定期增加innodb_undo_logs并且重新性能測試。
7.以理想的配置部署到生産環節。
性能和可擴充性考慮
把undo logs放到另外的檔案裡面允許MySQL統一的維護I/O和記憶體。如undo資料被寫入磁盤并且很少被使用,就沒必要檔案系統記憶體cache,可以把更多記憶體給buffer pool使用。
内部
實體表空間檔案已undoN命名,N是空間ID
InnoDB計算innodb每個表的統計資訊機幫助優化器查找最有效的執行計劃。這個特性預設是啟動的,通過innodb_stats_persistent參數。
可以通過innodb_stats_persistent_sample_pages采樣page個數。是否自動重新計算統計資訊通過參數innodb_stats_auto_recalc控制。當資料有大于10%被修改就會重新統計。
如果關閉了innodb_stats_auto_recalc,需要通過analyze table來保證優化器統計資訊的準确性。當新索引被增加到表中,索引統計資訊會被計算并且添加到innodb_index_stats表上不管有沒有開innodb_stats_auto_recalc。
在建立表時,可以使用innodb_stats_persistent,innodb_stats_auto_recalc,或者使用create table和alter table的stats_persistent,stats_auto_recalc,stats_sample_pages子句。後者會覆寫前者。
統計資訊在服務重新開機後被清理,在表下次被通路的時候重新計算。統計資訊使用随機采樣,2次統計資訊可能不一樣,會導緻不同的執行計劃。
配置innodb優化統計資訊采樣
MySQL查詢優化器使用評估的統計資訊來選擇索引。采樣page個數通過設定參數innodb_stats_persistent_sample_pages,預設為20。
修改采樣率時考慮一下狀況:
1.若統計資訊不夠優化器選擇的計劃可能不是罪理想的。統計資訊準确性可以通過使用select distinct和mysql.innodb_index_stats對比。
innodb_stats_persistent_sample_pages太少會導緻統計資訊不夠準确,太多會導緻分析執行太慢。
2.analyze table太慢可以減少采樣率,若太少會導緻統計資訊不準。
InnoDB持久化統計資訊表
持久化特性依賴于MySQL内部的表管理,innodb_table_stats和innodb_index_stats.
innodb_table_stats:
Column name
database_name
資料庫名
table_name
表名,分區名或者子分區名
last_update
最後一次更新時間戳
n_rows
表中資料行數
clustered_index_size
聚集索引page個數
sum_of_other_index_sizes
非聚集索引page個數
innodb_index_stats:
index_name
索引名
stat_name
統計資訊名
stat_value
統計資訊不同值個數
sample_size
采樣page個數
stat_description
描述
從MySQL 5.6.6開始統計資訊預設是持久化的。通過參數innodb_stats_persistent控制。優化器通過統計資訊來選擇索引。Innodb_stats_transient_sample_pages控制采樣pages個數,預設為8。Innodb_stats_transient_sample_pages可以runtime設定。
Innodb_stats_transient_sample_pages在innodb_stats_persistent=0的時候影響采樣。注意點:
1.若值太小,會導緻評估不準
2.若果值太大,會導緻disk read增加。
3.會生産很不同的執行計劃,因為統計資訊不同。
在MySQL 5.6.6,預設啟動統計資訊持久化,預設innodb_stats_on_metadata為0.可能會減少schema的通路速度,若表或所有太大。
當MySQL Client以—auto-rehash啟動,innodb所有的表都會被打開,相關的索引統計資訊都會被更新。
不管innodb_stats_transient_sample_pages是什麼,選擇一個值會被有太多I/O有能保證統計資訊相對準确。
Analyze table的複雜性依賴于:
1.innodb_stats_persistent_sample_pages
2.被索引的列數
3.分區個數
複雜度=采樣個數*索引列*分區個數
有4種InnoDB螢幕:
标準InnoDB監視有一下資訊:
1.每個活躍事務保留的表和記錄鎖
2.事務鎖等待
3.線程信号量等待
4.挂起檔案的IO請求。
5.buffer pool統計資訊。
6.清理和insert buffer合并活動
InnoDB鎖螢幕提供額外的鎖資訊。
InnoDB表空間螢幕列印出所有共享表空間中的segment,驗證表空間配置設定的資料結構
InnoDB表螢幕列印innodb内部資料字典。
當可以啟動innodb螢幕定期輸出,innodb會定期輸出到mysqld标準錯誤輸出。一般會輸出到錯誤日志中。
innodb會把診斷輸出到stderr或者檔案中,不會輸出到buffer中,以免buffer溢出。SHOW ENGINE INNODB STATUS輸出,每個15秒鐘都會寫入到一個狀态檔案,innodb_status.pid,檔案在服務關閉後被删除。pid是服務的程序id。隻有在innodb-status-file=1的情況下才會被建立。
innodb螢幕可以在使用時啟動。但是最好隻在想要看的時候啟動,螢幕會照成一定的性能下降。如果把螢幕資訊輸出到相關表,如果忘記把表關閉了你的錯誤日志可能會變的很大。
啟動标準innodb螢幕
啟動螢幕定時輸出:
CREATE TABLE innodb_monitor (a INT) ENGINE=INNODB;
禁用标準螢幕定時輸出:
DROP TABLE innodb_monitor;
MySQL 5.6.16之後,可以使用參數innodb_status_output來啟動和禁用。
set GLOBAL innodb_status_output=ON;
需要時輸出标準螢幕
mysql> SHOW ENGINE INNODB STATUS\G
啟動InnoDB鎖螢幕
啟動定時輸出
CREATE TABLE innodb_lock_monitor (a INT) ENGINE=INNODB;
關閉定時輸出
DROP TABLE innodb_lock_monitor;
MySQL 5.6.16之後,啟動innodb鎖螢幕,需要設定innodb_status_output,innodb_status_output_locks。
set GLOBAL innodb_status_output_locks=ON;
因為标準螢幕會輸出鎖資訊。是以啟動鎖螢幕必須全部配置。
啟動InnoDB表空間螢幕
啟動定時輸出:
CREATE TABLE innodb_tablespace_monitor (a INT) ENGINE=INNODB;
關閉定時輸出:
DROP TABLE innodb_tablespace_monitor;
啟動InnoDB表螢幕
CREATE TABLE innodb_table_monitor (a INT) ENGINE=INNODB;
DROP TABLE innodb_table_monitor;
鎖監控和标準監控基本一樣,特别是鎖資訊部分。如果啟動了标準監控和鎖監控,其實是一個輸出流,就是多了額外的鎖資訊。
輸出段
Status:
顯示時間戳,螢幕名,生産結果基于之前幾秒鐘
BACKGROUND THREAD:
srv_master_thread顯示,主背景顯示是如何工作的。
SEMAPHORES:
輸出線程等待信号量和統計資訊關于多少次spin等到,等待mutex或者rw-lock。大量的線程等待,在innodb中可能是磁盤IO,和資源争用問題。innodb_thread_concurrency減少并發線程,可以減少并發。spin rounds per wait顯示每個os wai等待mutex的spinlock的rounds。
LATEST FOREIGN KEY ERROR
這個資訊是關于最近的外鍵錯誤。
LATEST DETECTED DEADLOCK
最近的deadlock資訊。
TRANSACTIONS
目前資訊鎖等待資訊報告,可以發現鎖沖突。
FILE I/O
顯示I/O線程資訊,執行各種不同類型的I/O。由innodb_read_io_threads和innodb_write_io_threads來控制這些線程個數。
INSERT BUFFER AND ADAPTIVE HASH INDEX
顯示innodb insert buffer和自适應hash index,和各自的統計資訊。
LOG
顯示了innodb log資訊,目前log順序,flushed的log,checkpoint的log資訊。也顯示了挂起的寫入和寫入性能資訊。
BUFFER POOL AND MEMORY
page的寫入和讀取統計資訊。
ROW OPERATIONS
顯示了主線程的行為,包括每個類型行操作的性能。
參考:
<a href="https://www.percona.com/blog/2006/07/17/show-innodb-status-walk-through/">https://www.percona.com/blog/2006/07/17/show-innodb-status-walk-through/</a>
InnoDB表空間螢幕輸出在共享表空間中,檔案segment和驗證表空間配置設定資料結構。表空間螢幕不描述由innodb_file_per_table配置設定的表。
整體的表空間資訊:
FILE SPACE INFO: id 0
size 13440, free limit 3136, free extents 28
not full frag extents 2: used pages 78, full frag extents 3
first seg id not used 0 23845
id:表空間id
size:目前表空間的page個數
free limit:free list沒有被初始化的最小的page number。
free extents:free extents個數。
not full frag extents:沒有被完全填滿的extent。
used page:被配置設定的pages。
full frag extents:被配置設定滿的extents。
first seg id not used:沒有使用的第一個segment ID
segment資訊:
SEGMENT id 0 15 space 0; page 2; res 160 used 160; full ext 2
fragm pages 32; free extents 0; not full extents 0: pages 0
id:segment id
space,page:表空間号 0 表示共享表空間,page号 2表示inode
res:segment保留的page
used:segment配置設定的頁的使用。
full text:被完全使用的extent
fragm pages:配置設定的初始化。
free extents:空閑的extents
not full extents:不滿的extents
pages:非滿的extents使用的page
熱備
percona 也出了一個免費的熱備工具具體可以看:
<a href="http://www.cnblogs.com/Amaranthus/p/3922570.html">Percona XtraBackup User Manual 閱讀筆記</a>
冷備
冷備就是在mysql服務關閉之後,複制走所有的檔案。
替換備份類型
另外一種備份類型是mysqldump+binlog的方式。在之前有介紹。
執行恢複
innodb恢複在服務啟動時自動運作。若出現損失或者磁盤錯誤,必須通過備份恢複。可以使用checktable來檢查表是否順滑哦。有時候page順壞,可能是系統的檔案緩存造成的,而不是磁盤資料。最好的方法是重新開機電腦。
innodb crash恢複有一些步驟:
1.應用redo log。如果redo log找不到了就會被跳過。跳過redo log會加快恢複過程,但是不建議。
2.這一步可以并發執行:
a.復原沒有完成的事務。
b.insert buffer 合并,把insert buffer修改到secondary index上。
c.清理,删除删除标記的記錄,不需要再被活動事務可見。
InnoDB複制和MyISAM複制沒什麼差別。
對于為master安裝一個新的slave,複制innodb表空間和log檔案,也要複制innodb表的frm檔案。把複制移動到slave上,如果innodb_file_per_table啟動,還要複制ibd檔案。
master中事務失敗,并不影響整個複制,MySQL複制是基于binlog的,事務失敗并不會被寫入bin log。
master上外鍵的級聯炒作,隻有在slave上也有外鍵并設定了級聯,才有效果。
因為網上有對比性能測試,內建memcached性能遠不如memcached。是以不做筆記
常用troubleshooting指南:
1.若出現錯誤,或者bug,檢視error log
2.若關系到deadlock,啟動了innodb_print_all_deadlocks,所有死鎖資訊都會列印到error log中。
3.發生DDL錯誤,無法打開innodb檔案,就會有system cannot find the path specified錯誤。
4.當troubleshooting最好在指令行執行。
5.啟動innodb螢幕擷取錯誤資訊,若問題和鎖有關啟動lock 螢幕,若和DDL有關開table螢幕。InnoDB臨時啟動标準螢幕輸出,要一下條件:
a.長型号等待。
b.innodb不能buffer pool中空閑的block
c.67%的buffer pool被lock heap或者自适應hash index占用
6.使用check table診斷錯誤表。
排查步驟依賴于問題發生在啟動時,還是執行DML和DDL語句等。
初始化問題
如果innodb在試圖初始化表空間或者日志檔案出錯,删除所有innodb建立的檔案然後嘗試重建。最簡單的方式是以指令行啟動,就可以看的很清楚。
runtime 問題
如果在炒作檔案是,innodb列印一個作業系統問題,如下方式解決問題:
1.保證innodb檔案目錄存在,innodb log目錄存在
2.保證mysqld有通路權限
3.保證mysqld可以讀取配置檔案
4.保證磁盤空間未滿
5.保證資料檔案目錄沒有沖突。
6.檢查innodb_data_home_dir和innodb_data_file_path的值。
為了查詢資料庫page損壞,可以使用select into outfile通常是沒有問題的,嚴重損壞會導緻innodb背景操作crash,觸發assert,導緻redo crash。
這時候使用innodb_force_recovery強制innodb啟動,阻止背景操作執行,這樣可以dump表。
innodb_force_recovery = 1
在使用參數錢保證已經做了備份,并從小的值開始遞增,使用到了3以上要先在測試環境嘗試,MySQL 5.6.6之後4以上都是隻讀的。
innodb_force_recovery預設是0,高值包容低值的特性。
1(SRV_FORCE_IGNORE_CORRUPT)
如果發現損壞page,讓服務繼續運作。
2(SRV_FORCE_NO_BACKGROUND)
阻止master thread和任何清理線程運作。
3(SRV_FORCE_NO_TRX_UNDO)
crash recovery之後不運作事務rollback
4(SRV_FORCE_NO_IBUF_MERGE)
防止insert buffer merge操作運作
5(SRV_FORCE_NO_UNDO_LOG_SCAN)
當啟動資料庫的時候,不檢視undo log
6(SRV_FORCE_NO_LOG_REDO)
不使用redo log來恢複,這個值隻能select * from t複雜的語句會導緻錯誤發生。若表中的損壞不能讓你dump全表資料,可以使用order by pk desc部分導出。為了安全起見不能使用寫入。5.6.16版本之後4以上隻能隻讀。
表定義儲存在frm檔案和innodb資料字典中,若移走frm檔案或者服務crash資訊會變的不一緻。
CREATE TABLE問題
當error log有以下錯誤,表示有資料字典資訊但是沒有資料檔案。
InnoDB: Error: table test/parent already exists in InnoDB internal
InnoDB: data dictionary. Have you deleted the .frm file
InnoDB: and not used DROP TABLE? Have you used DROP DATABASE
InnoDB: for InnoDB tables in MySQL version <= 3.23.43?
InnoDB: See the Restrictions section of the InnoDB manual.
InnoDB: You can drop the orphaned table inside InnoDB by
InnoDB: creating an InnoDB table with the same name in another
InnoDB: database and moving the .frm file to the current database.
InnoDB: Then MySQL thinks the table exists, and DROP TABLE will
InnoDB: succeed.
打開表問題
mysql輸出如下錯誤:
ERROR 1016: Can't open file: 'child2.InnoDB'. (errno: 1)
如果error log有以下錯誤,表示有遺留的frm檔案
InnoDB: Cannot find table test/child2 from the internal data dictionary
InnoDB: of InnoDB though the .frm file for the table exists. Maybe you
InnoDB: have deleted and recreated InnoDB data files but have forgotten
InnoDB: to delete the corresponding .frm files of InnoDB tables?
被遺忘的中間表
如果alter table時crash,可能會有遺留的中間表。中間表名以“#sql-”開頭。可以在資料目錄上看到,表螢幕,還有INFORMATION_SCHEMA庫的表中看到。
移除遺留的中間表,執行一下步驟:
1.确定中間表,是修改前,還是修改後的。可以通過表螢幕或者INFORMATION_SCHEMA的INNODB_SYS_TABLES或者INNODB_SYS_COLUMNS和INNODB_SYS_INDEXES查詢表結構。
2.一旦确定是alter前,或者alter後,建立一個和中間表一樣的資料庫目錄。
ysql> CREATE TABLE tmp LIKE employees.salaries; ALTER TABLE tmp DROP COLUMN to_date;
Query OK, 0 rows affected (0.02 sec)
Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0
3.複制到資料目錄
shell> cp tmp.frm employees/#sql-ib87.frm
4.删除中間表
mysql> DROP TABLE `#mysql50##sql-ib87`;
Query OK, 0 rows affected (0.01 sec)
5.如果左邊能夠覆寫#sql-*.frm檔案,删除。出現錯誤可以忽略
mysql> DROP TABLE `#mysql50##sql-36ab_2`;
ERROR 1051 (42S02): Unknown table 'employees.#mysql50##sql-36ab_2'
表空間消失錯誤
如果啟動了innodb_file_per_table,出現以下錯誤
InnoDB: in InnoDB data dictionary has tablespace id N,
InnoDB: but tablespace with that id or name does not exist. Have
InnoDB: you deleted or moved .ibd files?
InnoDB: This may also be a table created with CREATE TEMPORARY TABLE
InnoDB: whose .ibd and .frm files MySQL automatically removed, but the
InnoDB: table still exists in the InnoDB internal data dictionary.
解決步驟如下:
1.在其他資料庫目錄中建立相符的frm檔案,并且複制到資料庫目錄中。
2.drop原來的表,這樣可以成功删除表,并且innodb可以列印警告到錯誤資訊,ibd檔案消失。
以下items表示innodb如何錯誤處理:
1.如果運作超出空間,出現table is full錯誤并且innodb復原錯誤處理。
2.事務死鎖復原事務,重試整個事務。鎖逾時innodb隻復原一個等待逾時的語句。當事務復原,因為死鎖或者鎖等待逾時會取消事務内所有語句,如果以start transaction或者begin語句開始,rollback不會取消語句,後面的語句會變成事務的一部分知道commit或者rollback或者隐式送出的語句。(mariadb 測試中發現,關閉自動送出和start transaction一樣,隻復原出錯語句。)
3.重複鍵錯誤復原sql語句,如果語句沒有指定ignore選項。
4.行太長錯誤,復原SQL語句
5.其他錯誤由MySQL層代碼發現,復原相應的SQL語句。