是某羣的哥們義務翻譯的,宣傳一下,還沒時間時間讀,粗濾看了所有翻譯完了300多頁佩服javascript
https://github.com/CMant/Mastering-MariaDB- 原地址:若是你須要讀,請star一下php
Mastering MariaDB 中文譯本 原著:Federico Razzoli 譯者:蟲神 寫在前面的話: 這個項目,姑且稱之爲項目吧,從去年10月份就開始了。當時官網掛的仍是mariadb10.1。今年的4月份其實已經翻譯完了,可是還須要大量的整理工做。斷斷續續的,持續到如今。截至到發版以前,我又上MariaDB的官方網站看了看,穩定版已經更新到10.2 了。xtradb已經被廢棄,換成了innodb。看了看緣由,巴拉巴拉說了一堆。其實用咱們高中物理老師的一句話就能夠歸納——「懶」。固然,除此以外,MariaDB基金會還在percona XtraBackup 的基礎上開發了mariadbbackup,用以備份。實測了一下,安裝更加方便,功能也更強大。原文描述爲「based on and extended」。 也就是說,本書如今並非最新的了,不只是小版本小功能的區別,甚至在存儲引擎級別也作了重大的調整。可是閱讀這本資料並不會有什麼太大的影響。一本書,若是能吸取它80%的知識,那麼就已經算是很不錯了。 關於這本書的英文原版,我須要說幾句。這本書很是適合有oracle基礎的dba來閱讀,若是對ACID和oracle的系統架構瞭解的比較深刻,那麼閱讀本書將會很是容易。我是在地鐵上下班的期間讀完的。以爲這本書很好,而後又想去作一點別人不敢想或者想了懶得去作又或者作了一半沒能堅持下去的事:翻譯它!自我11年開始進入大學學習時,就有了一個想要翻譯一本技術類英文原著的想法。沒想到時隔6年,才終於實現。翻譯這本書到一半的時候,其實我是有點堅持不下去的。可是想了想本身吹下的牛與已經付出的辛苦。咬了咬牙仍是堅持下來了。 翻譯的質量其實並非太好,各位讀者還請多多包含。我畢業於河北科技師範學院,學歷是專科,四級考了兩次都沒過。但好在自己比較喜歡英語,並且技術類單詞也有限。咬咬牙仍是翻譯了下來。在翻譯本書的過程當中也發現了原著中的一些錯誤。我並不是是MySQL方面的專家,對MySQL也並非很是熟悉,因此對原文中的全部知識點去進行驗證的也很是有限。可是若是原文與事實有誤被我查出來的,我都在旁邊作了標註。至於一些原文的邏輯錯誤。好比前言不搭後語的,也都標註了出來,其中還貼了一些原文上去供讀者自行參詳。 「我只是但願,在本身不斷成長的道路上,能夠爲這個行業去作點什麼。」咱們在QQ羣裏吹水的時候,感謝這位大哥給予了這樣的評價: 除去翻譯這本書,早在讀大學的時候,那時候爲了完成數據庫做業,老師要求有客戶端,C,B不限,大部分同窗都在用VB,PHP,JAVA或者去DOWNLOAD一份的時候,我腦子一抽,決定用C++和QT作一個客戶端出來。當時關於qt的資料中文版很是少。我當時也僅僅是參考了國外的一套qt視頻和國內的一些博客。完成做業以後,我又作了一套c++ QT教程,放在本身的博客上,算是國內僅有的幾個(??)公開免費放出來的QT中文視頻教程了吧。(喏,這就是地址,當年我還瘦着呢 blog.sina.com/cotxtan)。沒想到竟然還有淘寶賣家拿去賣。銷量慘淡 。 關於行文,由於水平和時間都有限。行文不順暢和排版不統一的地方請多多包涵。我是雙魚座,別噴,我玻璃心。 關於發佈,我會把PDF和WORD版本都放在GITHUB上,若是哪些大神看到了其中某些錯誤,無論是我翻譯的仍是原文的錯誤。能夠直接在原版上進行標註。我會感謝你們貢獻的知識。 關於盈利 壓根就沒想過這回事 本書相關參與者 Josh King 供職於Kualo Web Hosting 擔任高級系統軟件工程師,在數據庫管理方面有着十多年的工做經驗。 同時他也是一名高性能系統和linux內核開發專家。做爲幾個著名軟件組織成員之一,爲linux和開源項目發展作出了巨大的貢獻。好比LOPSA和免費軟件基金會 他專一於基於windows和BSD平臺的高可用和雲相關的解決方案,被LOPSA授予 傑出專業信息技術獎。同時,他還編寫了大量基於linux系統的調優文檔。 他如今和他的老婆孩子定居德州。 Dainiel parnell 早年有大量計算機技術相關的經驗,開始工做接觸的機器就是AIM-65,後來有VIC-20,Commodore 64,Apple2 Commodore AMiga,ICL concurrent cp/m86 目前他是個果粉。用的都是mac。 Dainiel parnell喜歡用Ruby在Rails上處理他的醫療工業網站。前端玩javascript,後端搞Erlang. Dainiel parnell在工做和思考之餘喜歡和家人待在一塊兒。不幸的是,他6歲的兒子在去年死於一種被稱爲板條疾病的神經系統錯亂疾病,沒法醫治。 Giacomo Picchiarelli 是一名在數據驅動設計和MySQL管理方面有着6年工做經驗的軟件測試工程師。Giacomo Picchiarelli在linux系統和測試驅動開發上有着很強的技術背景。 Philipp Wollermann 現供職於谷歌德國公司,擔任軟件工程師,Philipp Wollermann搞Mariadb是由於他本身要用MariaDB,一晃就是5年。他還爲東京的 CyberAgent搞過web應用優化,數據庫性能調優。 關於做者 Federico Razzoli 是一名軟件開發者,數據庫專家和自由軟件支持者,他從2000年開始從事網站和數據庫應用方面的工做,而且在MySQL方面有較長期的工做經驗,如今是maraiadb社區的一名活躍成員 關於譯者 蟲神,充滿浪漫與才情的DBA,一點也不出名 14年畢業於河北科技師範學院計算機網絡技術專業。 現就任於天津一家金融公司,擔任DBA。 關於本書 簡單介紹一下這本書,本書並非給菜鳥來作入門的,可是若是你和我同樣屬於當了很長一段時間的的oracle database管理員,對關係型數據庫比較瞭解,對於acid的過程比較清晰,有良好的系統架構基礎知識,那麼這本書能夠做爲你用來學習MySQL類數據庫的快捷工具。徹底水平過分,不會讓你有浪費時間的感受。對於oracle dba,徹底感受不到這本書哪裏難以理解。 若是您沒有學習過任何關係型數據庫。我建議您在讀過learing MySQL and MariaDB或者其餘相關基礎書籍以後再來讀這本書。由於這本書的做者也是這麼建議的。 目錄 (我連頁碼都沒作。) 第一章:Mariadb學習必知 Mariadb架構 命令行客戶端 存儲引擎 Xtradb和innodb tokudb myisam和aria 其餘 日誌 MariaDB 緩存 Innodb數據結構 認證和安全 information_schema 數據庫介紹 performance_schema 數據庫介紹 與MySQL想通之處以及其餘一些dbms MariaDB 資源 總結 第二章 排錯 MariaDB報錯概覽 SQLSTAT 值 ERROR 編號 ERROR 消息 自定義錯誤 show warnings 和 show errors 命令 診斷區 GET DIAGNOSTICS 命令 錯誤日誌 錯誤日誌格式 經過錯誤日誌排錯示例 系統日誌 通常查詢日誌 通常查詢日誌格式 general_log 表 經過通常查詢日誌排錯示例 日誌機制 刷新日誌 基於文件的日誌循環 基於表的日誌循環 SQL_ERROR_LOG 插件 存儲過程排錯要點 使用SQL_ERROR_LOG插件對存儲過程排錯 第三章:優化查詢 慢查詢日誌 慢查詢日誌文件格式 slow_log表 來自Percona Toolkit的pt-query-digest命令 索引介紹 表統計信息 存儲引擎和索引 用EXPLAN命令研究執行計劃 理解explan輸出 select 樣例 內部臨時表,文件 union查詢 索引訪問方法 join子句中的索引優化 子查詢優化 總結 第四章:事物和鎖 innodb 鎖 鎖模型 鎖類型 鎖診斷 sql語句中的鎖 一致性讀 非重複讀 幻讀 一致性讀 讀鎖 死鎖 事物 事物的聲名週期 事物的隔離級別 read uncommitted 隔離級別 read committed 隔離級別 repeatable read 隔離級別 serializable 隔離級別 事物訪問模型 元數據鎖 總結 第五章:用戶和鏈接 用戶帳戶 經過角色受權 經過secure socket layer(ssl)鏈接到MariaDB 認證插件 線程池觸發 監控線城池 配置線程池 UNIX上配置 windows上配置 優化配置變量 解決線程池中阻塞的線程 監控鏈接 進程狀態 斷開鏈接 總結 第六章 緩存 innodb cache innodb page innodb buffer pool new page和old page buffer pool 實例 髒頁 優先讀優化 診斷buffer pool性能 導出和導入buffer pool innodb buffer切換 雙寫buffer myisam key cache LRU和中點插入策略 key cache 實例 key cache 段 預加載索引 aria page cache 查詢cache 配置查詢cache 查詢cache相關信息和狀態 子查詢cache 替代查詢緩衝方案 爲表建立cache 基於獨立會話的cache 總結 第七章:innodb 表壓縮技術 innodb壓縮技術引言 innodb壓縮條件 「file-per-table」模式 innodb文件格式概要 建立innodb壓縮表 innodb壓縮表實操 監控innodb壓縮性能 innodb_cmpmem 表 innodb_cmp_per_index 表 innodb_cmp 表 其餘壓縮方案 總結: 第八章:備份和災難恢復 備份種類 邏輯備份和物理備份 熱備份和冷備份 全量備份和增量備份 備份和複製 備份操做步驟 經過mysqldump建立dump文件 純文本備份 mysqldump命令中的 -tab選項 mysqlimport導入dump文件 經過select...into outfile 建立純文本文件 經過show create table 命令導出表結構 經過load data infile導入dump 文件 利用選項分離操做 建立和還原dump文件示例 在connect和csv存儲引擎上操做備份 物理備份 什麼文件應該被複制 表文件 日誌文件 配置文件 熱物理備份 文件系統快照 經過rsync命令實施增量物理備份 非停機的文件複製 爲增量備份使用 binary log percona xtrabackup 備份實操 全量備份 部分備份 備份 完整備份 部分備份 還原備份 還原完整備份 還原部分備份 備份安全 修復表 回覆innodb表 校驗表 事物日誌 強制數據回覆 修復 非innodb表 check table 命令 repair table 命令 修復csv表 經過myisamchk和aria_chk工具修復表 myisam和aria自動恢復 總結 第九章:主從複製 複製引言 複製如何工做 複製線程 並行複製 「從」端日誌 選擇 binary log 格式 基於語句的 bingary log 基於行的binary log 混合binary log 存儲過程當中的binary log 配置主從複製 配置一個新的「主」 配置一個新的「從」 啓動「從」 檢查「從」是否運行 從新配置已有的「從」 導入數據到「主」 從」主「導入數據到」從「 從」主「中導出數據 從」從「中導出數據 過濾binary log 條目 SET SQL_LOG 命令 @@skip_replication 變量 在」從「中過濾複製條目 校驗binary log 條目 配置並行複製 讓」從「懶一點 多」主「一」從「複製 複製日誌 循環binary log 循環 relay log "從"日誌狀態 檢查複製錯誤 checksum table 命令 pt-table-checksum 工具 文件校驗 查詢校驗 排錯 」從「不啓動 」從「延遲 總結 第十章:表分區 分區支持 分區類型和分區表達式 分區表達式 索引和主鍵 分區名稱 分區類型 range類型 list 類型 columns 關鍵字 hash和key類型 linear關鍵字 分割子分區 管理分區表 查看分區信息 更改分區定義 修改range和list分區 修改hash和key分區 分區和表之間複製數據 操做語句機制 分區的物理文件 優化查詢 分區修剪 分區檢索 總結 第十一章:數據分片 多個磁盤間分散文件 選擇表文件的路徑 innodb日誌文件 配置undo 配置redo FEDERATEDX和connect 存儲引擎 建立FEDERATEDX表 定義遠端服務器鏈接dblink 建立 mysql connect 表 發送sql語句到遠端服務器 合併多了個connect mysql 表 SPIDER存儲引擎 SPIDER工做原理 安裝SPIDER存儲引擎 建立SPIDER表 查詢和錯誤日誌 遠端服務器上執行特殊語句 spider_direct_sql() 函數 spider_bg_direct_sql()函數 總結 第十二章:mariadb galera cluster mariadb galera cluster 關鍵概念 galera cluster 引言 同步複製 安裝集羣 需求 安裝 啓動節點 選擇節點url 節點規定 快照狀態傳輸 增量狀態傳輸 腦裂 galera 仲裁器 配置集羣 galera 中重要的系統變量 通常集羣設置 性能和可用性 設置快照狀態傳輸模式行爲 處理galera限制 設置wsrep參數 監控和排錯 告警腳本 檢查狀態變量 集羣健康狀態 獨立節點狀態 複製健康狀態 網絡性能 負載均衡 galera 集羣的限制 galera負載均衡 總結 索引 前言 數據庫與咱們的生活息息相關,咱們一天會使用好幾回然而你可能並沒意識到。好比,打電話算一個,訂酒店,訪問網站或者是其餘。 這些數據庫很是龐大複雜,可是它們有不少都是由mysql或者是mysql的同門兄弟mariadb組成的。 mysql是著名的LAMP四大組件之一,linux,apache,php和mysql。網站技術上用的最多的就是lamp。這就是爲什麼不少it從業者都據說過mysql。實際上mysql在上世紀80年代就有了。可是真正風靡整個it行業是在2000年到2001年。這段時間是動態網站技術爆發的一年。其免費,開源易學等特性使得mysql在網站領域大行其道。 因爲mysql天生勵志,它的不少功能特性增加很是迅速。曾經還被postgresql支持者嘲笑不支持不少DBMS的關鍵特性,好比事物和外鍵。可是沒多久,mysql就實現了這些功能,由於這些功能對於不少用戶都極爲須要(雖然普通用戶並沒有感知)。例如。它比postgresql支持主從複製早了10年。比postgresql更快更可靠。隨着時代的發展,mysql變成了一個功能完善,特性豐富的關係型數據庫 爲何Mysql之父Monty Widenius離開了這個項目,而去搞一個衍生產品MariaDb?原來在2005年,oracle買下了innodb存儲引擎,2008年,Sun公司買下了mysql,轉年又被oracle買下。從那之後,mysql彷彿陷入了一場巨大的陰謀當中:一個背景龐大的,持有不少專利和昂貴軟件的的商業公司霸佔了原本免費的mysql。真可謂,司馬昭之心路人皆知。 可是話說回來,咱們也必須認可oracle確實也花費了大量精力和資源投在了mysql身上。而且在一些方面作出了很大的貢獻,好比innodb。然而,天有不測風雲,誰能保證oracle會一直這麼作下去?要是有一天oracle把mysql閉源了呢?或許只有oracle負責人才能回答這些問題。 咱們能夠肯定的是,mysql如今彷彿並不像從前那麼開放了。oracle員工開始對公佈出的bug有所保留。沒有相關信息或測試在意發佈的版本是否有安全漏洞。更新也有點疲軟。而且一些社區網站,那些包含大量mysql信息的wiki站也都不見蹤跡了。 就在此時,一隻異軍在社區網站忽然崛起,它就是mariadb。不少重要的新特性,好比多源複製和角色功能都是最早被社區成員開發出來的。mariadb的bug跟蹤紀錄和項目管理模式容許咱們去了解在整個過程當中有什麼bug,什麼新特性。「新版本是什麼樣的?」,"它何時發佈?"諸如此種問題,一些活躍的開發者還會與用戶進行郵件,或者是IRC溝通。當mysql的文檔開始變得專有隱蔽的時候,mariadb的文檔將會一直免費下去,而且經過公共wiki提供社區支持。 最重要的,mariadb有基金會,跟apache基金會同樣.Monty Widenius是這些收益的負責人。有錢,咱就能保證mariadb的源碼一直免費安全的發展下去。不只如此,基金會的存在,還使得mariadb衍生出一些周邊產品,好比《mariadb knowledge base》mariadb基金會網站以下:https://mariadb.org 從2009年的那一天,mariadb和mysql就走上了不一樣的道路。當mysql的開放程度愈來愈小氣的時候,mariadb依然豪放地擁抱着全世界。這種開放精神纔是科技進步的靈魂。來自全世界的mariadb的開發者和用戶全身心地投入到mariadb成長過程當中,共同造就了mariadb的今天。 這本書包含了管理mariadb和集羣服務相關的技術。對你在mariadb數據庫開發和管理上大有裨益。mariadb將會一直兼容mysql最新的特性。這本書的開始會講一些讀者應該瞭解的基本特性和機制。其中包括不少真實環境中的問題,好比mariadb 報錯,日誌,鎖。你將會學習到如何提升服務器的查詢性能。同時還包含了如何選擇恰當的備份策略和恢復技術,使用複製功能完成數據切片,mariadb galera集羣,spider存儲引擎相關的,好比診斷,排錯方法也會詳細說明。無論是來自mysql的特性,仍是mariadb獨有的特性,都會在本書涉及。插件和相關工具的開發社區也會提到 mariadb已經枕戈待旦,隨時等待高性能和高可用的危機。來吧,讓咱們一塊兒進入mariadb的世界。 內容簡介: 第一章:mariadb學習必知。探討了一些關鍵特性和組成。好比存儲引擎和日誌。一些最重要的mariadb相關專業資源也會在這裏涉及 第二章:排錯,闡述了mariadb中如何處理bug,mariadb如何生成錯誤,咱們能夠從哪裏找到這些報錯。 第三章:優化查詢。主要講了查詢的優化,首先咱們討論了須要找出哪些操做致使了慢查詢的出現。然後又討論了mariadb優化器去執行一個查詢時使用的相關算法,好比索引合併和子查詢優化算法。 第四章:事物和鎖。闡述了mariadb在併發狀況下如何使用鎖來保證每一個事物之間的隔離,以及鎖是如何影響性能的 第五章:用戶和鏈接 討論瞭如何管理mariadb中活動的鏈接和用戶帳戶。包括權限問題,用戶資源獲取,認證方法,ssl鏈接,以及線程池、 第六章:cache 闡述了存儲引擎的cache技術。innodb buffer pool,myisam key cache,以及aria page cache。隨後又提到了查詢和子查詢方法,以及其餘緩存結果集的方式。 第七章:innodb 表壓縮 討論了innodb壓縮表技術。爲咱們展現瞭如何建立一張壓縮表而後監控它的性能。最後還比較了不一樣的壓縮方案 第八章:備份和災難恢復 闡述了mariadb和第三方工具提供的備份方法。以及如何選擇一個備份計劃,不一樣的備份種類以及在須要的時候如何還原它們 第九章 複製 講述瞭如何搭建一套複製環境。以及mariadb 10.0中包含的最新特性,即並行複製和多源複製 第十章 表分區 爲咱們展現瞭如何把大表分割成幾個分區,分區文件存放在不一樣的存儲設備上。不一樣的分區類型,以及根據不一樣狀況如何選擇最優分區類型等等都會涉及到 第十一章: 數據分片 探討了把數據經過多個磁盤和服務器分佈存儲的主要方法。這些存儲引擎容許讀寫遠端服務器數據,諸如spider, federatedx ,connect. 第十二章: mariadb galera cluster .涉及到mariadb的集羣技術。闡述瞭如何配置集羣,添加節點,監控性能,以及解決通常問題。 爲了學習這本書,你須要有: 運行任何操做系統的PC機,linux是最優選擇,由於mariadb最有可能運行在linux上,而且本書也基本專一於linux系統。然而,這些命令能夠不被修改地運載在任意UNIX系統中。有必要的話,咱們也會提到windows mariadb 和mariadb galera cluster能夠在mariadb官方網站上下載到。須要的第三方工具會在相關章節說起。其中涉及到的系統命令,不出意外每一個linux版本應該都有 誰會學這本書? 這本書應該算是mariadb或者是mysql的中級讀物,若是你對mariadb有一個比較清晰的認知,能夠管理mariadb服務,或者配置安裝。固然沒問題。若是你是其餘關係數據庫的專家,固然也沒問題。但若是是剛入門,仍是建議先去讀一讀《mariadb knowledge base》這類的初級讀物。 特別說明的是,這本書的讀者應該熟知如下幾個知識點 1 關係數據庫的基本概念 2 sql語句,至少基本水平 3 配置文件的語法和結構 如下幾個知識點,若是讀這本書的話倒不是很必要,可是仍是推薦你最好學習一下 1 如何編寫windows或者linux 的自動任務 2 如何編寫能與mariadb交互的腳本 3 mariadb程序,好比存儲過程,事件,觸發器 讀者反饋(我爲何要翻譯這個??): 很是榮幸能得到讀者的反饋,以便讓咱們知道您是如何看待這本書。哪裏喜歡,哪裏以爲寫得很差。讀者的反饋對於咱們是最大的饋贈。 反饋能夠經過寫一封簡單的郵件到feedback@packpub.com,受累以這本書的標題做爲郵件標題發送便可。 若是本書中有些內容是您所專長的,您能夠發表您的文章或者是您的書籍。做者專欄在www.packtpub.com/authors 客服: xxxxx(不議) 下載示例代碼: 您能夠從www.packtpub.com 下載全部的示例代碼文件,前提是您已經購買過的書。若是您是從別的地方買的,您能夠訪問www.packtpub.com/support 註冊一下,而後咱們會直接發郵件給您 errata xxxx piracy xxxx questions 您能夠經過questions@packpub.com聯繫咱們,若是您對此書有任何疑問,咱們將會竭誠爲您服務。 第一章 mariadb學習必知 這章主要描述了mariadb的一些架構知識,再次聲名,並不意味着第一章就是能給初學者看的。其中有些知識吃透了才能理解這本書 本章咱們將討論如下幾方面 1 mariadb 架構 2 sql語句工做流程 3 命令行 4 存儲引擎和其餘特性 5 日誌 6 cache 7 用戶認證和權限 8 information_schema和 performance_schema數據庫 9 與mysql同源分支和其餘dbms 10 資源網站 mariadb架構 Monty Widenius 在2009年開發了mysql的衍生版本----mariadb,此數據庫由社區開發維護Monty Widenius是mysql之父。惋惜後來mysql被oracle收購了。初版的mariadb基於mysql 5.1開發出來。之後的版本通常都和mysql的版本號是同樣的,有些特性是和percona server 同樣的。另外一些特性則很是像當今的一些主流產品。 取自percona的一個很是重要的功能就是xtradb。這是innodb存儲引擎的一種衍生版本。innodb是如今mysql和mariadb中的默認存儲引擎。xtradb修補了一些oracle發佈innodb時候就暴露出來的,可是oracle懶得去解決的漏洞。同時它還有一些小的性能提高和新特性。諸如協議,api,以及許多sql語句,凡是能在mysql中跑的,在mariadb中通通沒問題。即使是爲mysql寫的插件一樣OK。正因如此,一些基於mysql的應用程序能夠不加修改地遷移到mariadb上。可是話說回來,若是你想用以前mysql沒有的,可是mariadb有的特性,可能不行。若是開發人員不關心這些特性。那麼應用程序能夠跑在這兩種數據庫上。讀者通常都是有必定的關係數據庫基礎知識,如今我們快速瀏覽一下mariadb的架構。在本章的開始,已經列出了全部組件。剩下的就是在本章詳細地探討它們。 架構圖以下: 如你所見,mariadb接收sql語句,解析,而後返回結果集。讓咱們看看詳細過程是如何進行的 1 當客戶端鏈接到mariadb的時候,會認證客戶端的主機名,用戶,密碼,認證功能能夠作成插件。 2 若是登陸成功,客戶端發送sql命令到服務端 3 解析sql語句 4 服務端檢查客戶端是否有權限去獲取它想要的資源 5 若是查詢已經存儲在query cache當中,那麼結果當即返回 6 優化器將會找出最快的執行策略,或者是執行計劃。也就是說優化器能夠決定什麼表將會被讀,以及哪些索引會被訪問,哪些臨時表會被使用。一個好的策略可以減小大量的磁盤訪問和排序操做等,這部份內容咱們將會在第三章的 優化查詢中討論。 7存儲引擎讀寫數據和索引文件,cache用來加速這些操做。其餘的諸如事物和外鍵特性,都是在存儲引擎層處理的。 mariadb和存儲引擎使用日誌來記錄接收到的語句,發生的錯誤,數據變動等等。大多很多天志都是可選的,然而,有些日誌對於管理工做是必須的。好比binary log 用來備份和複製。日誌會在後面的章節講解。 mariadb有一些選項能夠影響服務器的行爲。其中不少是動態的,意味着你能夠在服務器運行的時候改變它們。也有一些是靜態的,意味着服務器一旦啓動就不能再變。有一些變量是會話層的,意味着能夠在任何當前獨立鏈接的的會話中改變它們,有一些是全局層的,改變將會影響到全部用戶。有幾種方法去決定在影響範圍。好比經過命令行參數,命令文件。若是是動態變量,經過sql語句便可。mariadb經過命令讀取配置文件。具體的路徑要取決於操做系統。通常來說,一臺服務器運行一個mariadb實例。由於只用到一個配置文件。linux上是 /etc/my.cnf ,windows是在mariadb的安裝目錄。好比這種 c:\mariadb 10.0\my.ini 然而,這種模塊化的配置方式在同一臺機器上安裝多個mariadb實例時是很是有用的。一些設置能夠對全部實例生效。可是每一個實例還能有本身獨特的設置或者是覆蓋常規設置。配置文件也能夠放在用戶的home目錄中。可是此時只有在使用 --user 啓動mariadb的時候纔會被讀到。經過命令行指明的參數將會覆蓋到配置文件中的參數。這種方式在測試不一樣版本,不一樣變量的性能時很是有用 本書不會描述全部的選項,讀者應該對最重要的幾個參數很熟悉了。若是您想看全部參數的話,《Mariadb knowledge base》裏面都有。 Mariadb實例其實就是個mysqld文件。在linux上,能夠直接運行,可是通常都是由mysqld_safe腳原本調用。mysqld_safe腳本既能夠啓動實例,又能夠重啓意外終端的實例。在生產環境中比mysqld更安全。mysql.server腳本能夠用在system V架構之下。這個腳本通常都會根據linux發行版從新命名,當一臺服務器上安裝了幾個實例的時候,極可能會被命名成mysql_multi 命令行客戶端 本書使用的示例都是在命令行中操做的,學習命令可以極大的提升效率。 mysql客戶端檢測命令結束是經過 ; , \g , \G 來識別的。下面的例子演示了這一點 //* 下載示例代碼 開篇說了,要麼你註冊帳號在他的網站上買書,買哪本才能下哪本的。若是你在別的地方買的這本書,就得去他那裏註冊帳號,而後他發郵件給你,郵件地址 http://www.packtpub.com/support *// mysql客戶端通常會有個提示符,當你剛鏈接到數據庫的時候是這樣的 在提示中,[none]表明了沒有選中任何數據庫,意思就是每次你執行sql語句的時候,數據庫的名字必須被特別指定。使用use命令能夠選擇一個默認數據庫。它的名字將會出如今提示中。好比這樣: 當一行語句太長不得已分紅兩行的時候,提示符會變成這個樣子: 若是咱們忘了輸入結束語句的符號,那麼提示符就會變成這個樣子來讓咱們注意到問題所在: 好比這裏,mysql客戶端不知道語句結束了,由於結束符號忘了輸入了。 若是在一行的結尾有個單引號,那麼單引號會出如今新的一行當中。新一行能夠經過敲回車來輸入新的字符,不過大多數狀況會出錯。好比下面這種狀況。提示符幫助咱們注意到了問題所在: 此處的問題所在是 「hello world」 後面的單引號沒輸入,故單引號會在下一行的提示中出現。 有時候命令行輸出結果難以閱讀,尤爲是輸出結果比命令行一行還長的時候。這種狀況下,在命令的結尾輸入\G 能夠轉換顯示方式,好比這樣。(就是把行轉成一頁。參考plsql developer上面的功能) 在linux系統中,能夠使用 pager 程序來讀取過長的輸出結果。 pager經過關鍵字或者鼠標滾輪實現了翻頁輸出功能,諸如此類的命令有 less , more,lv (不少發行版中默認沒有安裝) 。好比咱們使用less命令。能夠這麼輸入: 以後的查詢就能夠經過 less來查看。若是但願關閉pager功能。運行下面的命令便可 有時候輸出超級長,可是咱們也就關心其中的幾行,或者就一行。那麼針對這種狀況。咱們能夠使用pager中的 grep命令做爲選項。下面的例子向咱們展現了 「show engine innodb status」 這個命令。其中咱們只關心線程狀態,其中只要包含 「I/O thread」 這個字符串便可 另外一個比較有意思的選項是pager功能中的 md5sum 命令。若是採用了這個命令。當一個查詢執行的時候。其對應的 md5 hash值也會顯示出來。這在比較兩條查詢結果集的時候很是有用。好比下面,咱們檢查兩張表是否徹底同樣 在上面的例子中。查詢結果會經過md5sum進行計算。他們的md5值會出現再命令行中。如你所見,值是相等的。所以咱們能充分肯定 t1 t2 是相同的 \tee 命令能夠用來把當前客戶端會話記錄到文本文件中。在 windows 系統中。能夠使用文本編輯器打開編輯。此時\p 再也不有效。中止記錄的話,使用 \notee 命令便可 默認狀況下,sql語句warning 級別的警告不會出如今命令行中,可是會顯示一個警告數。若是有警告,說明sql沒有按照咱們但願的形式運行。若是想看到全部的警告 ,使用大寫的 /W 便可。若是要取消這種警告方式。再輸入 小寫的 \w 便可 上面的例子中。咱們首先打開了警告提示,隨後的select查詢就生成了一個詳細的警告內容。而後咱們關掉了警告提示。再執行一樣的語句,就只有一個警告數量了。 所謂工欲善其事必先利其器,當咱們須要在命令行輸入複雜的語句的時候。能夠輸入 edit命令或者 使用EDITOR環境變量來設置一個默認的編輯器,好比linux上默認的vi或者emacs(不要再由於這種事打架)。 mariadb 10.0 中,中止服務器無需使用 強制退出或者新開個控制檯窗口調用mysqladmin命令。經過sql命令便可,即shutdown。 和其餘不少管理命令須要super權限不一樣。這個命令有個單獨的shutdown權限能夠配置。一般是隻有root有這些權限。退出客戶端使用 小寫的 \q 便可。示例以下: mysql客戶端能夠使用一種稱爲batch的文件。這個文件能夠編寫大量的sql語句。能夠用來作好比恢復邏輯備份,或者根據應用須要建立一個數據庫。執行的結果也能夠單獨寫到一個文件中。語法是UNIX類的風格。可是windows下也能夠用。好比這樣: 若是想不登陸客戶端,直接在shell中執行一個命令而後看到結果。你能夠這麼作(真實的狀況是你還要輸入 -u -p參數) 存儲引擎 正如以前章節所說,存儲引擎在物理層管控數據。它負責數據文件,數據,和索引cache。這使得管理和讀取數據變得更高效 每一張表,都有一個.frm 文件。這些文件包含着表的定義。經過服務器來建立和使用它們。 使用 「show engines」 命令或者經過查詢 information_schema.engines表能夠查看存儲引擎相關變量。下面的示例展現了標準的 mariadb 10.0.6中存儲引擎安裝狀況 以上輸出中,有一列名爲 support,表明了在當前服務器中此存儲引擎是否可用 當表被建立的時候,能夠指定一個存儲引擎。若是沒有指定,那麼就使用默認參數來建立。默認參數經過系統變量 storage_engine 來配置,如圖: 在 information_schema 數據庫中,有一張 tables 表,其中有一列叫作 engine,其表明的就是此張表用的什麼存儲引擎,示例以下: Xtradb和innodb innodb在 mariadb 5.5 和mysql 5.5中爲默認引擎。 percona搞了一套innodb的衍生產物—— xtradb。percona修補了innodb中的一些bug,不只如此,它還有一些innodb沒有的特性(主要是在性能和監控方面)。默認狀況下,mariadb使用xtradb引擎。固然和mysql中的 innodb是兼容的。在命令行中依舊使用「innodb」這個名字來表明xtradb。不管是查看引擎狀態仍是建表。 固然這種行爲能夠在編譯階段修改。任何新的代碼都會有新的bug或者是意料以外的性能問題。xtradb也不例外。 //* 本書xtradb統稱爲innodb。除非咱們在說一些innodb中沒有,可是xtradb有的特性的時候 *// innodb 是一種高性能存儲引擎。它支持不少功能,好比savepoint,XA,外鍵。savepoint能夠在事物執行中任意位置間插入一個狀態標記,以備須要時恢復到事物執行的某一點中。XA是一種特殊的事物,主要用來調用多個資源節點,也就是咱們常說的分佈式。在大多數狀況下 innodb比其餘引擎性能更好。因爲此種緣由,本書專一於xtradb,除非特別說明。爲方便起見,這裏把xtradb統稱爲innodb。除非咱們在討論一些innodb不支持的特性的時候。 innodb事物經過一種複雜的鎖機制和undo日誌來實現。每一個鎖能夠針對一行或者多行進行操做。行經過索引進行定位。若是必要,undo日誌能夠用來回滾事物,undo日誌能夠存儲在系統表空間或者是其餘地方。 TokuDB 這套引擎由tokutek開發,在mariadb 5.5.中被收錄。強制安裝可是能夠選擇是否開啓。它支持savepoint事物,XA,可是不支持外鍵和全文索引。和innodb有很大不一樣。它主要的特性是針對索引使用了一種新的數據結構——分形樹。這種結構和一般的B樹很類似,可是它每一個節點都有個buffer,這些buffer裏面包含了那些更深層的要變動的節點的數據。僅當buffer滿了纔會把這些變動一塊兒應用。若是這些變動須要寫磁盤,那麼這就成了一個很重要的優化點,由於更少的寫入和更大的塊在性能上一般更快。正因如此,分形樹數據結構不會存在碎片問題。 TOkuDB的另外一個重要的特性是數據壓縮,固然,具體的壓縮級別取決於數據集。可是通常比其餘的存儲引擎有着更好的壓縮比。使用這種策略的緣由是以前提到的寫操做都是一組一組一塊兒進行的。TOkuDB的數據壓縮特性不可關閉。 分形樹和壓縮功能使得TOkuDB更適合那些數據集太大以致於不能徹底塞進內存的狀況。就負載狀況來說,速度更優於innodb。除此以外,TOkuDB在性能和功能上就有點疲軟了。 myisam和aria 在mysql和mariadb5.5以前,myisam曾經是它們的默認存儲引擎。這種引擎對少許寫,大量讀進行了優化。從經驗上來講,myisam很是適合用於常常往表中插入數據,可是不多有修改和刪除操做的數據倉庫或是報表系統。 myisam寫每張表須要涉及兩個文件:數據文件和索引文件,索引文件被毀是沒事的,由於它能夠被重建。複製數據文件(包括.frm文件)來對myisam表進行異機恢復是可行的。 myisam有三種數據格式:固定,動態以及壓縮。固定格式指的是表中的每列長度是固定。換言之動態格式就是能夠動態調整(相似char和varchar)以節約空間。固定格式速度更快更可靠而且更不容易產生碎片。壓縮格式能夠用來建立比較小的只讀表。 aria是被用來設計做爲myisam的繼任者的。它支持日誌和數據災難恢復。aria中的數據改變是原子級的。要麼所有應用,要麼所有失敗。aria使用一種不會產生碎片且速度更快的被稱爲PAGE的數據格式。可是它也能夠使用固定或者動態格式用來兼容myisam,可是這樣表就再也不支持災難恢復了。(crash-safe ) aria在併發性的表現上要優於myisam,而且《mariadb knowledge base》一樣建議在新環境中部署aria存儲引擎。誠然,用戶仍是會感受到aria在併發寫入上的不足,尤爲是有多個索引的時候。 myisam和aria都不支持事物和外鍵,可是正如以前所說。每個在aria表上執行的語句均可以被看做爲一個事物。並且這兩種存儲引擎都是支持全文索引的。 MRG_MYISAM存儲引擎也被叫作MERGE,可以創建在多張相同的myisam表上。經過這種方式,能夠繞開操做系統的單個文件最大大小。 其餘引擎 上面描述的存儲引擎在通常場景都是能夠應付得來的。固然也有一些特殊的環境須要一些其餘的存儲引擎才能解決。其中有一些引擎使用了非標準的輸入輸出方法,或者是非標準的查詢方法,下面咱們就展現一些極爲特殊場景下的存儲引擎。 1 OQRAPH 存儲引擎由OPENQUERY開發。它擁有數和圖的數據結構。數結構在數據庫中有幾種方法操縱,可是不管使用哪一種方法,都有其缺陷,由於其相關的理論並不很是適合樹形結構。OQGRAPH解決這些問題是經過把sql請求轉譯成特殊的樹請求(這方面接觸的少,不大清楚具體內容)。OQGRAPH在maria db5.2引入,在5.5版本暫時中止,在隨後的mariadb10版本中又從新引入。 2 BLACKHOLE存儲引擎繼承自mysql 。BLACKHOLE表永遠都是空的。修改永遠不會生效,查詢永遠都是空結果集。 3 SPIDER存儲引擎由kentoku shiba開發。它經過其餘mariadb實例讀寫數據。支持XA事物。SPIDER主要設計用來作數據分片,關於數據分片內容咱們會在第十一章 數據分片 中討論。 4 CONNECT 存儲引擎是mariadb中一種特殊的存儲引擎。用來從外部資源中讀寫數據。其對應的數據資源能夠是mariadb或者myslql,ODBC鏈接,文件,甚至是目錄。文件能夠是但不限於CSV,HTML表,二進制數據,其提供了API來支持不一樣的文件格式。數據可以被壓縮成gzip。一個connect表能夠用來從其餘表傳輸數據。例如,能夠把數據重組或者表合併成一張彙總表。CONNECT頗有可能會廢棄一些比較老的存儲引擎,好比CSV這種訪問CSV文件的引擎;FEDERATED一樣是一種繼承自mysql的存儲引擎,它也能夠向CONNECT那樣鏈接到其餘mysql或者mariadb實例的表。後來mariadb引入了federatedx,由於federated已經沒人維護了。 5 ARCHIVCE存儲引擎主要是用來壓縮表。可是它有幾個限制,好比插入數據後不能修改或刪除,並且還至關慢。在當下環境,innodb,myisam或者是tokudb,表現都比archive好不少。 6 cassandraSE存儲引擎是用來鏈接apache cassandra nosql的,它能夠在mariadb的數據類型和cassandra的邏輯之間轉換。他是mariadb特有的存儲引擎,由於它須要使用mariadb的動態列來模擬cassandra的列族。 7 SphinxSE 存儲引擎主要是容許mariadb訪問存儲在sphinx 數據庫服務器中的表。sphinx的優點在於它出色的全文檢索功能。 8 mroonga存儲引擎是專門爲全文檢索設計的。它包含了日語,中文,韓國的字符集和語言。它經過快速幾何索引爲地理定位作出了優化。 9 sequence存儲引擎不可以被建立成一張物理表。若是啓用它,語句須要包含一些有着明確分隔符命名的虛擬表。??因爲這種命名,sequence存儲引擎會返回一系列數字。例如 seq_1_to_10 虛擬表返回1到10的結果集。seq_1_to_10_step_2一樣會返回1到10 的結果集,惟一不一樣的是它的步進是2. 11 performance_schema 存儲引擎僅僅被performance_schema數據庫做爲內部表使用。這就是爲何DBA會意識到有一些特定的語句存在,好比"show engine performance_schema satus" 這種命令能夠用來查看 performance_schema數據庫的內存佔用量。 日誌 mariadb服務器包含如下幾種日誌類型: error log:這種日誌包含了服務器運行時產生的錯誤。其包含了服務器錯誤(好比再啓動過程當中某個插件意外中止)和sql錯誤 SQL_ERROR_LOG: 這是一個在mariadb 5.5引入的插件,以sql語句寫入文件的方式來記錄生成的錯誤。相比error log,它只記錄 sql錯誤。使用這種方法來檢查存儲過程或者觸發器中的錯誤是很是容易的。 general query log: sql執行語句會被寫入到文件中 slow query log: 這種日誌主要用來記錄那些執行時間很長或者是沒使用索引的查詢。這種日誌用來找出應用程序或者數據庫緩慢的緣由是很是有用的。 binary log(binlog):依賴於特定的格式,這種日誌會把數據變動記錄成二進制格式。這種日誌再實施增量備份,複製或者是數據庫集羣技術的時候會用到。 relay log:這種日誌僅存在於 「主從複製」的從端,其包含了從主端接收到的數據。從端的每一條relay log都對應着主端的一條binary log。 innodb 包含了兩種稱爲 undo log和redo log的日誌。undo日誌用來記錄活動事物的變動向量(oracle中是這麼解釋,其實就是能夠理解爲變動前的映像)而且在有必要的時候回滾它們。redo日誌用來記錄請求的數據改變,而且能夠用來進行實例恢復。 aria 有一種稱爲 aria log 的日誌,其包含了那些沒有應用到數據文件的數據。它能夠用在數據庫啓動階段對那些由於沒有正確關閉數據庫而致使的表錯誤進行恢復。對應的myisam 表日誌就叫作 myisam log。 每一種日誌都有其本身的一類文件。通常存儲在數據庫安裝目錄中的data目錄。若是你特別指定,也能夠放到其地方。然而,一些日誌能夠寫到mysql數據庫的系統表中,這種寫入方式比較慢,可是它容許經過sql語句來查詢相關信息。若是此時你使用的時csv存儲引擎,那麼你能夠把這些日誌以一種流行的格式導入到外部程序中。 因爲日誌寫入很是頻繁,所以使用buffer來提升寫入性能。(經過批量寫入以減小開銷)固然了,寫入日誌會使得系統更加可靠。有一些變量能夠調整buffer大小,dba能夠根據須要的可靠性和速度作出相應調整。 日誌會被週期性循環使用。意味着新的記錄會寫入到新的文件中,最老的文件可能會被刪除。這種循環能夠是自動進行(好比 binary log),也能夠是用過FLUSH LOGS命令或者是mysqladmin工具 對於每一種用戶須要讀取的日誌,都有相應的工具能夠展現其內容。日誌循環能夠經過red hat linux中的 mysql-log-rotate腳本完成 mariadb cache (由於cache和buffer 均可以被翻譯成緩存,可是實際上咱們知道意義不大同樣,所以不作翻譯) mariadb 有幾種不一樣的 cache能夠經過不一樣的系統變量和啓動參數根據特定的工做負載進行調整。一般來講,只有不多的幾種日誌須要去配置。經過改變幾個小的選項,整個服務器性能可能會有巨大的改變。有一些cache可以解決不少特殊的問題。 innodb 中的 buffer pool 應該說是最重要的一種cache,其包含了innodb表的數據和鍵。在一套專用服務器系統中,一般buffer pool的大小爲物理ram的70%。固然,這個值不是絕對的。最優值取決於不少因素。buffer pool有兩個子鏈:new list和old list,其鏈大小也是能夠配置的。其規則爲:最小老化值的頁必循存在於new list中。其設置決定了new list中能夠保存最近多久讀取到的數據,或者是在old list中在被移除以前保留多久。爲提升併發性,能夠配置更多的buffer pool 實例。不一樣的實例之間不會包含相同的數據 change buffer ,是buffer pool中的一塊區域,用來存放那些尚未寫入磁盤的數據。對於寫入比較多的狀況,change buffer可能會佔用大量的buffer pool。對於讀比較多的狀況,change buffer佔用不多,甚至能夠關掉。它也能夠配置爲僅存儲特定類型的變動以適應負載狀況。 myisam 使用一種稱爲 key cache的buffer,它不存儲數據,只存儲索引。若是有多個key cache實例,它們也能夠被獨立地配置。 aria 使用一種和myisam的key cache很類似的被稱爲 page cache的buffer。aria的page cache對於固定長度數據格式速度更快。可是aria目前還不支持多個cache實例。 若是myisam或者是aria存儲引擎做爲主要引擎。那麼key cache或者page cache應該設置爲與須要常常訪問的索引文件相同的大小。 表被打開時會被放入cache,並存儲物理文件句柄(句柄是C++中的叫法,可是大體意思是通用的)。myisam和aria對每張表使用兩種文件。(由於索引和數據文件是分開存放的)這種cache方式能夠減小數據文件過熱的狀況。 當相客戶端連接到服務器時,其對應的帳戶處於阻塞狀態,那麼主機的cache中會包含客戶端鏈接到服務器的ip地址和主機名等相關信息,以在必要時阻斷鏈接。 innodb數據結構 mariadb中,如以前所說,innodb就表明了xtradb。 innodb有一種稱爲表空間的東西,表空間是一種能夠存放索引和表的文件。在老版本的mariadb和mysql中。全部的表都建立在system表空間中。若是 innodb_file_per_table 系統變量設置爲1 (mariadb10版本以後的默認值),那麼每張表都會存儲在單獨的表空間中。這個值是動態的。所以,你可讓一些表獨立存放成文件,而另外一些放在system表空間中。 system表空間默認狀況會包含 innodb數據字典,undo日誌,change buffer,以及 doublewrite buffer。數據字典是集合了全部innodb 表,列,和索引的元數據信息。system表空間以 ibdata 文件格式存放在 data目錄中(默認兩個文件)。 表空間的一部分叫作段,常規表空間包含一個數據段和每一個索引的索引段。系統表空間有幾個段。(原著並未繼續說明) page是一種存在於表空間或者buffer pool中的更小的存儲單元。Page大小可調整。一個page能夠包含一行或者着多行以及剩下未佔用的空間。非空的比例叫作 fill factor(填充因數?其實就是page佔用率) 在change buffer中被修改的page叫作dirty page(髒頁) 在某些狀況下,好比一致性讀過程。innodb會連讀讀取幾個page,總量達到1MB。那麼這樣的一組page叫作 extends。 innodb重點不只是在讀取,而是在鎖機制,每條索引都至關於一個鎖。 innodb 索引分爲 clustered index(彙集索引?)和secondary index(二次索引?)主鍵是 clustered index。若是一個表沒有主鍵,那麼第一個包含非空列的惟一索引會做爲主鍵列。若是連這個都沒有。那麼會自動建立一個隱藏的cluster index。全部的secondary index記錄的葉子節點都指向cluster index 記錄。所以咱們說,secondary index包含了 clustered index (實際上clustered inxdex 等同於oracle的索引組織表,而二級索引等效於常規索引,只是二級索引在檢索時會經過clustered index做爲一個跳板來定位記錄。譯者注) 認證和安全 mariadb認證基於用戶名,密碼以及客戶端主機(或者是ip地址),用戶名和主機構成了一個帳戶,以下+ user_01@localhost 每個用戶能夠使用不一樣的認證方式,這在使用外部系統登陸的時候額外有效。例如,操做系統帳戶。mariadb或者認證插件會根據客戶端提供的密碼來決定是接受仍是拒絕鏈接。 權限能夠配置給獨立的帳戶或者是使用like通配符的一組帳戶。其中的一些權限能夠容許執行特定的語句類型,或者是限制一類語句。權限能夠應用到整個服務器,具體的設置對象能夠是表或者視圖中獨立的列。這使得決定在什麼帳戶能夠操做什麼對象這方面有極細的粒度和極強的彈性。 mariadb 10 同時支持角色功能,權限能夠分配給角色而不止是帳戶。而後再給帳戶授予相應的角色。若是一個用戶被授予了一個角色,那麼他就有了這個角色所具備的權限。角色提高了批量用戶權限管理的效率,同時它也是一種很安全的方式。 固然還有一些額外的選項,好比dba能夠要求用戶必須經過ssl來加密鏈接,dba也能夠對用戶作出資源限制,或者是以爲用戶是否能夠同時建立多個鏈接副本(也就是容許一個帳戶屢次併發登陸)。 information_schema database information_schema 數據庫(方便起見有時候叫作 I_S),是一個包含表信息的虛擬數據庫。其庫中的表能夠分紅幾個類別。 1 metadata 元數據表:像 schemata,tables ,cloumns 包含了數據庫的結構信息,好比表,列等等 2 status and variable 狀態和變量表: GLOBAL_VARIABLES和SESSION_VARIABLES 表包含服務器的系統變量。GLOBAL_STATUS和SESSION_STATUS表提供了服務器的操做選項信息。 3 privilege 權限表:這些表以用戶名爲開頭,後跟_PRIVILEGES,包含了每一個用戶對應每一個對象的權限。 4 PROFILING 表:這種表用來監控當前會話中的執行的查詢,還能夠看到服務器的一些底層操做。 5 processlist表:這些表展現了活動的會話和他們的狀態 其中innodb提供了幾張信息表,有一些是xtradb特有的。這些表以 innodb_或者是xtradb_開頭。 1 innodb lock: INNODB_LOCKS,INNODB_LOCK_WAITS,INNODB_TRX表包含了活動的鎖,等待,和事物申請的鎖或者是等待的鎖。 2 INNODB buffer pool :這些表以INNODB_BUFFER_開頭,其中包含了 buffer pool和頁使用狀況信息。 3 INNODB_METRICS :這些表提供了innodb的一些底層操做。 4 INNODB compression :這些表以INNODB_CMP開頭,提供了頁壓縮的性能相關信息。 5 INNODB full-text :這些表以INNODB_FT_開頭,提供了innodb表中關於全文索引的信息。 6 INNODB data dictionary :這些表以INNODB_SYS_開頭,提供了innodb表,列和外鍵的一些元數據信息。同時也包含了關於文件的統計數據和信息(數據字典表,同oracle) 通常來講,這些信息能夠經過查看 information_SCHEMA數據庫或者是經過show命令顯示。查看information_schema數據庫更加靈活和標準,可是比較麻煩。 innodb的活動信息能夠經過易讀的格式展現出來,好比經過「show engine innodb status」,「show engine innodb mutex」語句 爲了檢索information_schmea數據庫,服務器必須打開並讀取數據文件,這些操做速度緩慢,所以,這種常常在生產環境中執行的查詢最好只讀取必要的文件,好比簡單的方法就是加個where條件。 performance_schema 數據庫 在mariadb代碼中,關於性能監控信息的詳細結果都會寫入到一個特殊的數據庫中———performance_schema。 可是,監控性能信息會致使服務器性能降低,再可是,你能夠在控制文件中關閉它,經過設置 performance_schema變量爲0 performance_schema變量基於如下幾個概念。 1 actors 一個actor是一個監控線程,能夠監控用戶鏈接或者是mariadb的後臺線程 2 consumers :consumers一種用性能數據填充的表 3 instruments : 指明瞭數據庫哪些對象開啓了什麼監控。例如wait/io/file/sql/binlog等 4 object:是一些必須被監控的活動表 爲了決定服務器如何被監控,能夠設置 performance_schema 中的 setup表:setup_actors setup_consumers setup_instruments setup_objects . 當performance_schmea開啓,且此時有底層操做任務發起的時候,若是開啓了 actor,consumer,instrument和object的監控。那麼新的信息將會寫入到performance_schema中。setup_timer表用來決定監控項目的時間粒度(微妙,納秒等) performance_schema中的 setup類表由幾張表組成,其中一些重要的表遵循命名規範,即基於先後綴。前綴表明了這類表能夠提供什麼信息,最重要的前綴好比這些: events_statements_: 涉及sql語句 events_stages_:sql語句執行狀況(好比解析和表打開) *_instances_: 包含根據不一樣類型的鎖進行分類的信息,好比 mutex_instances_ 就是互斥鎖 events_waits_: 表包含了線程等待鎖被釋放的信息。 後綴標識的表擁有一些彙總數據,好比: _current: 只包含當前活動鏈接 _history :僅存放一些受限的歷史信息。 _history_long : 包含了更多的歷史信息。 其餘一些後綴,其意義見名知意。 例如,events_waits_current 表列出了當前線程的等待事件.events_statements_history 表展現了最近執行過的語句的相關信息。 比較mysql和其餘DBMS: 每個版本的mariadb都是基於對應版本的mysql修改而來。例如,mariadb 5.5基於 mysql5.5.當mysql的結構更新的時候,mariadb會修補其bug而且增長新的特性。mariadb徹底兼容Mysql。也就是說,mysql上面能夠用的sql語句,api調用,配置文件在mariadb上徹底沒問題。(而且保證結果一致),若是有什麼未記錄在案的部分,將會被視爲bug。固然,mariadb會基於mysql代碼來開發一些新功能,所以若是是mysql不支持的功能,可能在mariadb上能夠使用,可是mysql就不行了。 在複製環境中,從mysql複製到mariadb是沒問題的,只要版本號同樣。可是!若是你使用了mariadb的新特性可能就不行了。 mariadb同時引入了percona server的一些特性。也就是說,若是僅使用percona server中的這些特定的功能,那麼percona server也能夠和mariadb很好的兼容。 這張表展現了mysql和mariadb的對應關係 每一對兒版本號相同的mariadb 和mysql 都是能夠兼容的,而且最新版本支持向下兼容。mariadb 10.0 打斷了這種傳統,由於它只使用了mysql 5.6中的一部分特性,所以並非徹底兼容的。詳細的兼容,不兼容列表請看 《mariadb knowledge base》。大多數狀況下沒什麼問題,除非用戶想在複製環境中把mysql 5.6和mariadb 10.0混用。好比 mysql 5.6能使用innodb表做爲一種中間層去作memcache,可是這項特性在mariadb中還不支持。 mariadb和mysql使用 「可執行提示」(executable comments)來提升與其餘dbms的 兼容性。可執行提示能夠在mysql和mariadb上執行sql語句的一部分,可是在其餘dbms上不行,也可能只能在mariadb,或者是最新的mariadb上。 好比 可執行提示能夠是這樣的: 若是加了 M 則這個命令只能執行在mariadb上 咱們看到的都是簡寫的版本號,下面這個命令能夠看到版本號是由5或者6位數字組成的:第一個或者前兩個數字是主要版本號,隨後的兩個數字是次要版本號,最後兩個數字是補丁號。例如: 須要注意的是,mysql 5.6上的 可執行提示在mariadb10.0上也能夠執行,幾乎徹底兼容,可是到了mysql 5.7版本就不必定了。 mariadb 資源 主要的文檔資源就是《mariadb knowledge base》也叫作KB。它包含了相關的開源工具,也是一個很好的交流技術的地方。 mariadb KB能夠從這裏找到: https://mariadb.com/kb/en/ mariadb 基金會有一個博客可讓用戶很容易地看到新版本的特性和一些其餘重要新聞,地址以下: https://mariadb.org/ planet mariadb彙集了mariadb的相關信息 http://planetmariadb.org/ JIRA工具能夠用來報告bug,瀏覽已知bug和修補狀況信息,也能夠瀏覽新發布的版本將會修補什麼bug和帶來什麼新的特性。地址以下: https://mariadb.atlassian.net/bnrowse/MDEV 總結: 在本章中,咱們大體瀏覽了mariadb的架構。解釋了不少的mysql客戶端的特性。這能夠提升DBA的工做效率和減小GUI工具的使用。 咱們討論了mariadb中引入的存儲引擎,別管是二進制仍是源碼。其中包括了innodb,tokudb,myisam和aria。innodb是本書主要講解對象,而且實際環境中也是大量使用,因爲這種緣由。咱們着重研究這個引擎和其數據結構。固然,可能因爲一些其餘緣由,在某些狀況下使用其餘存儲引擎性能更好。還會介紹一些比較小衆的存儲引擎,主要是能夠解決一些特殊需求。好比之後的章節中咱們會討論sipder引擎。在複製章節,咱們還會涉及到BLACKHOLE引擎用來避免複製某些數據。 咱們簡要地講了一些關於log的內容。其中有一些是使用mariadb特性必不可少的。好比物理備份,複製,誤刪後的還原。關於如何使用,咱們會在隨後的章節詳細講解。log在實際環境中必不可少。 最重要的概念就是cache和安全。後面會有一整章來詳細講解 information_schema和performance_schema數據庫包含了大量有用信息。本書不會詳細講解其所有內容。想看的從KB裏找。固然,在隨後的章節中,有些表會涉及到這兩個數據庫,咱們也會經過舉例來講明在實際環境中如何使用。 mariadb是mysql的衍生產物這個咱們已經討論過了。這個話題中最重要的莫過於在複製環境中用mariadb替換掉mysql時候可能產生的問題。或者是開發人員想開發一個能夠用在這兩個數據庫上的應用的時候(比較特殊狀況時開發人員想使用mariadb的惟一特性) 本章的最後列出了一些比較有用的mariadb相關資源。全部的高級用戶都應該常常保持良好的學習狀態,跟着時代的步伐前進,學到脫離這行爲止。 在下一章中,咱們將會學習若是使用日誌來找出mariadb中的一些錯誤以及如何調試sql語句。這些知識對於排錯尤其重要。而且在隨後的章節中咱們將會使用這些知識來處理一些複雜的狀況 第二章 錯誤調試 本章咱們將會討論一些關於mariadb服務器和sql相關的排錯知識,如下是本章涉及的幾個工具和技術要點。 1 錯誤產生緣由 2 診斷區 3 錯誤日誌 4 通常查詢日誌 5 日誌維護 6 SQL_ERROR_LOG插件 7 存儲過程排錯 理解mariadb中報錯緣由 在探討排錯技術以前,須要先搞清mariadb中通知用戶錯誤產生緣由的工具(能夠理解爲mariadb內置組件)。 mariadb中的錯誤告警由如下內容組成 1 SQLSTATE 值 2 error 編號 3 error 信息 ERROR通常是由服務器報出來的,用戶能夠使用signal和resignal異常函數去處理 爲了得到ERROR信息,mariadb提供了3個C語言接口 mysql_sqlstate(),mysql_errno(),mysql_error(). 幾乎全部的mariadb或mysql都有其對應的api接口。這些方法和語句將會在本章的隨後部分討論。如今,先讓咱們看看mariadb中的ERROR。 SQLSTATE 值 SQLSTATE值是一串5位數字。前兩位表明了錯誤類型和關於錯誤的通常信息。後三位表明了ERROR的子分類和具體的錯誤編號。若是子分類部分數字是000,那麼表明子分類沒法肯定。全部字符都是數字或者是大寫英文字母。 特殊值——00000 表明了成功。這是惟一的一個00類,而且這個值不能被用戶提出。01表明產生了一個請求操做的警告,可是其中的問題的一部分已經被跳過。02表明找不到,嚴格來講它不能算一個錯誤。反而還有多是用戶但願的,好比用遊標檢索行,當它讀取到最後一行的時候,就會產生這個錯誤。 其餘狀況下,若是錯誤發生,那麼相應的執行就會被中斷。對於非事務型引擎來講,這就意味着事物只執行了一半。若是你嘗試一次插入兩行,第二行包含了和某個主鍵重複的值時就會中斷。 就當前mariadb版本而言,有些狀況下會有一些沒法肯定錯誤。它們統一使用HY000代碼。也叫作general error. 此值表明從MySQL繼承的許多ERROR,以及大多數MariaDB特定的ERROR error 編號 error編號或者說是代碼,是一個smallint 類型的signed 值(最大爲32767),用來惟一肯定一種錯誤狀況。0表明了成功,不能被用戶當作異常拋出。 在同版本號下,mariadb和mysql的error編號基本同樣。mariadb特定的編號從1900起。這種特有的錯誤編號主要和mariadb的專有特性有關,好比虛擬列或者是動態列。 error 消息 error消息是有必定可讀性的長度爲varchar(128)的字符串。在最簡單的狀況下,不須要查看mariadb文檔,僅經過error消息就能夠知道具體錯誤緣由。有時候也會額外包含一些由於失敗操做而涉及到的一些表或者列名。 一般狀況下,error消息足夠說明到底發生了什麼錯誤。然而,若是error消息太難懂或者容易產生誤解,又或者是問題沒法很快解決,那麼用戶能夠經過error編號到mariadb文檔中查看詳細內容。 自定義error 自定義錯誤是用戶經過signal或者是resignal異常處理函數明確產生的。例如,若是存儲過程當中輸入了一個不正確的參數,那麼就會產生一個錯誤來代表問題緣由。比較好的是,signal函數能夠用在存儲過程以外,所以它能夠用來往SQL_ERROR_LOG中寫入錯誤,這些消息對於DBA或者是日誌讀取工具來講是頗有意義的。 用45000這個值來做爲用戶自定義錯誤號仍是很推薦的。mariadb,mysql和其餘相關衍生數據庫如今以致於到未來的某一版本都不能使用這個值。說回來,任何子類值爲000都是安全的,由於這樣的值與具體的錯誤無關(也就說無論主類編號如何,只要子類編號爲000,就是安全的)。因爲這種緣由,這種錯誤也是能夠被接受的。 //* 關於mariadb詳細錯誤代碼,請看《mariadb error codes》,網址https://mariadb.com/kb/en/mariadb-error-codes/ *// There could be valid reasons to use different SQLSTATE values; for example, a custom error in the 01 class is not fatal, and continues the execution. Another reason is mapping a custom error to a built-in error; for example, a custom error can be raised in a particular case when a duplicate key error occurs. A custom error is created to provide the DBA or the applications with useful information on how to debug the problem. However, you also probably want the application to take actions that it normally takes when a duplicate key error occurs. So, the custom error can use the same 23000 SQLSTATE value. //*The default error number depends on the SQLSTATE value: 1642 for warnings, 1643 for not found conditions, and 1644 for errors. These values are dedicated to user-generated errors. In these cases, the default error message informs whether the condition is a user-generated warning or an error. Otherwise, the default error message is an empty string *// Other condition properties exist in SQL standard and are partially supported in MariaDB. Such condition properties contain additional information about the cause of errors. They can be set for custom errors via SIGNAL and RESIGNAL, and they can be read via GET DIAGNOSTICS. However, these properties are not set for built-in conditions and are never returned to the client; so, developers normally ignore them show warning 和show errors 語句 mariadb的ERROR,WARNING都存放一個稱爲 diagnostics area 診斷區的地方。一般狀況下,診斷區包含了最近執行時產生的錯誤。可是關於診斷區具體的工做機制,包括如何存放,刪除錯誤信息將會在下一節講解。mariadb提供了一些sql語句容許咱們來查看診斷區的內容。 show warning 語句返回診斷區中當前產生的警告。show count(*) warning語句返回了警告數。這個值取自於warning_count 會話級變量。 以下圖,咱們展現了執行了一個能夠產生兩個警告的語句 輸出包含三列,錯誤代碼(CODE),錯誤消息(MESSAGE),以及錯誤級別(LEVEL),錯誤級別表明了錯誤產生的種類,其能夠是note(通常服務器消息),warning和error。若是你設置了@@SQL_NOTE=0,那麼note消息再也不顯示。 有些sql語句和系統變量能夠致使錯誤級別變化。好比使用 if exists和IF not exists選項時。它們本該產生error錯誤,可是經過加上這兩個子句,錯誤級別就改變了。 下面的例子展現了上述狀況。(其實就是加上了異常處理功能) 上面的例子中,咱們執行了兩個很是類似的語句,首先咱們使用了drop table刪除了一張本不存在的表,所以產生了error。隨後咱們使用if exists選項來刪除表,這就意味着若是表自己不存在,那麼mariadb不會產生error,可是warning仍是有。由於你可能須要知道這張表自己不存在。這個例子向咱們展現了level列的重要性。show warning語句會返回和這種狀況很是類似的結果,可能惟一不一樣的地方就在 本該是note的level,如今是warning。 正如以前所說,dba能夠決定是否把警告寫入錯誤日誌。sql子句能夠改變錯誤記錄行爲(好比使用if exists,if not exists或者是在dml中使用ignore)或者經過設置sql_mode系統變量來決定是否記錄更多可能出現的問題。若是你認爲有些錯誤你不怎麼關心,對系統也沒啥太大影響,設置的稍微不嚴格一些可讓你的日誌文件更小。 show errors 和show count(*) errors 語句和以前講的很是類似,不過它只能用來顯示和統計errors,不會顯示warnings或者notes。關於診斷區中errors的數量能夠經過會話變量 error_count來設置。 下面的列子展現了show count(*) warnings 和 show count(*) errors之間的區別 正如上例,嘗試經過if not exists子句建立數據庫,實際是存在的。所以,errors數爲0,warnings 爲1。 diagnostics area診斷區 診斷區分爲兩個子區域:statement信息和condition信息。 statement信息包含了兩個值: 1 number:這個值表明了存儲在condition區域的condition數量 2 row_count: 被修改的行的數量。這個值能夠經過 row_count() 函數和mysql_affected_rows() 接口返回。 寫入和刪除診斷區內容有着準確的規定,瞭解這些規則對於處理問題很是有用,能夠避免你走入排錯的陷阱,同時對於存儲過程排錯也是很是重要的。 不管如何一條語句都會生成至少一個狀態信息(note,warning,errors),任何新出現的condition信息都會使得以前的信息被刪除。然而有一個例外就是若是新的語句使用了resignal 或者 get diagnostics。那麼以前的狀態信息不會被刪除。這使得開發人員能夠在語句執行失敗時作出處理。若是語句因爲語法緣由不能被正確解析。mariadb不知道 resignal仍是get diagnostics,那麼此時診斷區會被清空 若是一條語句不產生任何信息,也不訪問任何表,那麼診斷區中老的條目得以保留,若是訪問了表,則老的條目會被刪除,即使語句自己不產生信息。 max_error_count 系統變量表明瞭診斷區中能夠存放的最大的消息數量。 如今,讓咱們看看診斷區是如何工做的,在下面的例子中,show warnings命令是用來查看整個診斷區最簡單的方法。經過設置SQL_MODE服務器變量爲錯誤的X來製造一個ERROR。 下例中,咱們先生成了一個錯誤,診斷區中會包含這個錯誤信息。 當咱們看見了診斷區這個錯誤以後,咱們執行一個正確的不訪問任何表的語句。沒有錯誤產生,而且診斷區中還保留原來的信息。 下例中,咱們用set來生成一個錯誤,隨後再用drop table生成另外一個錯誤。 上面例子中,因爲drop table訪問了相關表,診斷區被清空,所以show warnings只顯示了第二條錯誤。 下例中,咱們先生成一個錯誤,而後執行resignal生成另外一個錯誤。 如你所見,即使resignal語句正確地執行了,也不會清空診斷區,show warnings依然會返回兩條錯誤。再看下面的例子。咱們先生成一個錯誤,隨後執行一個正確的語句 如你所見,即使第二條語句不產生任何警告,可是診斷區仍是被清空了 GET DIAGNOSTICS 語句 GET DIAGNOSTICS語句是一種不錯的用來展現診斷區結構的工具,由於它會把每個值copy到一個變量中。 它的語法十分冗長且容易輸錯,可是它也是惟一一種能夠在存儲過程當中分析診斷區的方法。事實上,show warnings 給客戶端返回告終果集,可是不容許經過sql代碼訪問它。當具體的錯誤發生時,HANDLER會阻止語句繼續執行,可是又不提供相關的問題信息。 所以,能夠經過GET DIAGNOSTICS命令來展現診斷區中的內容。 先讓咱們往診斷區中填充兩個錯誤。咱們使用以前sql_mode=x的例子 如今使用get diagnostics來吧診斷區中的消息數變拷貝到一個變量中,而後使用select來查看。以下: 如今咱們知道它包含兩條項目。然咱們看一下 SQLSTATE值,記錄的數量,和記錄具體的內容,代碼以下: ERROR LOG 錯誤日誌包含了服務器啓動,關閉過程當中產生的錯誤。其包含了好比中止服務器或者在啓動中何種插件被阻止跟隨啓動以及數據錯誤。日誌能夠打開或關閉。 //*日誌默認存放在data文件夾中的文件。默認名爲 主機名.err .在複製環境中的不一樣主機名之間使用默認日誌名稱稍欠穩當,DBA應該專門去起個新名字。 *// windows中,若是沒特別設置,錯誤日誌是默認開啓的。errors能夠經過在控制檯經過 --console選項顯示。輸入 --log-error無效。 //* linux和unix系統中,錯誤日誌默認是關閉的。可是錯誤日誌仍是有的,它會被寫到標準輸出上,除非你用了nohup 之類指定了特殊的文件 *// 在全部系統中--log-error是用來開啓日誌的。它能夠指定日誌文件名稱和路徑(路徑可選,不寫默認放在data文件夾中)語法: --log-error=filename . 設置完畢後,路徑和名稱能夠經過 log_error 服務器變量讀取,只讀。 //* windows下能夠使用控制檯選項關閉,但不適於linux。若是多個服務器實例使用一個配置文件,那麼只要有一個實例用它,它就不能被關閉。另外一種曲線救國的方法是把日誌寫進/dev/null 中 *// 若是 log_warnings 變量大於0,則warning也會寫入到error 日誌中。若是這個值大於1,全部的鏈接錯誤也會被記錄下來。 error log 格式 錯誤日誌一行一條。當服務器啓動時,在最後一次關閉消息以後留下空行。 看個例子 首先咱們看到的是錯誤發生的時間。以 YYMMDD格式記錄。 隨後是一個空格和錯誤類型。其能夠是[Note] [Warning] [ERROR]表明了show warnings命令顯示的不一樣的錯誤類型。若是[]裏面是 mysqld_safe,意味着此條記錄被mysqld_safe 腳本記錄,這樣的行是關於服務器啓動和自動重啓的內容。 有些沒必要要的信息不會遵循這樣的格式,好比在服務器崩潰後的啓動中。這樣的信息毫不會寫入系統表。 有些系統中,異常關機會致使error log包含大量跟蹤信息。這能夠用來處理服務器問題。 經過error log 排錯示例 若是你linux系統上的mariadb服務器起不來,第一件應該作的事就是去看看error log。最新產生的error會在日誌的最下方,那些帶[error]標記的就是。 你能夠經過命令行在 error log中搜索帶有 error 標記的最後10行,其中涉及到兩個命令 tail—返回文件最新產生的行,grep—返回你匹配到的字符串。若是沒有權限,你能夠用sudo來獲取error log的訪問權。這些命令都是GNU 項目的一部分,幾乎全部的unix類系統裏都有類似的工具。若是要在windows中使用這些命令,你得須要一種叫作 Cygwin的東西。 開始執行試試: 第一行就告訴了咱們具體緣由所在,你在配置文件中設置了一個錯誤的變量(正確地應該是basedir而不是base_dir),第二行只是告訴你服務器要關機。可是顯然你應該已經明白該怎麼作。去配置文件中修改吧。 這個例子很簡單,可是要觸類旁通,此處的重點是查看error的步驟和問題解決的思路。 system logs mysqld_safe有一個 --syslog參數,這個參數會把錯誤記錄到系統日誌當中,除非你係統有日誌程序你才能這麼用,咱們會展現一個例子,通常在linux上這麼用。具體取決於日誌記錄程序,通常狀況下系統日誌中都會帶有 mysqld 或者是mysqld_safe這樣的標記來代表日誌來源。若是你服務器上安裝了多個mysql或者mariadb實例,那麼能夠設置多個前綴來區分日誌來源於哪一個實例。下例中使用了--syslog-tag選項來給服務器實例打個標記。 這樣,錯誤就會帶着一個 mysqld-serv1和mysqld_safe-serv1標記被寫入系統日誌。一般這些參數是寫到配置文件當中的。且只能寫到[mysqld_safe]下面。以下: windows系統中沒有syslog這個東西,可是日誌會被寫入到windows事件管理器當中。事件來源是以服務或者mysql來命名。warnings,notes和信息條目也不會遵循標準的日誌格式。 general query log 通常查詢日誌 全部發送到mariadb的語句都會根據接收順序依次記錄到 general query log 或者 general log中。這個順序毫不會和多線程環境的執行順序相等(由於語句一般會等待鎖釋放,此處說的意思是日誌順序是肯定的,不會產生混亂和衝突)。鏈接和斷開也會寫到general log中 general log通常用來找出應用程序bug致使的問題。 general query log依賴於binary log 格式.這個日誌將會在第八章備份和災難恢復中詳細說明。general log設計出來是爲了方便人們閱讀,binary log是方便程序讀。可是咱們能夠經過mysqlbinlog工具來讀取其二進制內容。這個工具會根據日誌格式,無論是statement,row仍是mixed來跟蹤數據庫的改變。你可能如今不明白,沒事,隨後的章節就會講到。可是須要注意的是,general log只在binary log 使用statement格式時有用。若是使用了mixed格式,那麼有些語句就不會被記錄進去了。 可以使用--general_log啓動選項來開啓general log,關閉設置爲0便可。默認是關閉的,可是這個變量是動態的,能夠隨時開啓關閉。 若是開啓了general log,默認存放在data目錄下,名字爲 主機名.log 。若是想指定別的路徑,須要設置 --general_log_file=filename 參數。在複製環境中,推薦給每一個服務器實例的general log專門指定一個惟一的名字 --log-output 選項決定了 error log和general log的寫入位置(隨後即談)。要記住的是這個變量是影響這兩個日誌。不能單獨設置。有三種選項FILE(日誌記錄到文件中),TABLE(日誌寫入到數據庫表),NONE(記錄行爲被抑制),若是想既寫入表又寫入文件,以下: 若是有NONE選項,其餘值被忽略。 此變量爲動態變量。能夠再運行時更改。爲全局變量,所以不能針對當前會話單獨設置。 有時候,超管用戶想關閉他本身的日誌記錄行爲。最可能的緣由就是他想改密碼(密碼會被清晰地寫入文件或者是表)。雖然不能針對每一個會話設置日誌輸出位置,可是能夠設置是否記錄,以下: 這個變量既能夠在全局設置,也能夠在會話中設置。所以若是有必要能夠關閉全部的日誌記錄行爲。 文件格式的general query log general query log 如下面的樣式做爲開始 服務器運行一段時間,通過一些查詢操做後,這個文件頭部變成了4列,其下有不少行,每行包含了服務器什麼時候啓動,什麼時候日誌被刷寫(日誌刷寫隨後講解) 以下: 日期列,以 YYMMDD HH:MM:SS 顯示時間,一般這個值能夠被忽略。 ID列,包含了鏈接的ID號,這和記錄在information_schema和performance_schema中的同樣,由connection_id()函數返回。 command列包含了用戶的操做類型,可能值是:connect,int db,query 和quit argument列的具體內容根據command不一樣而不一樣。在以前例子中,用戶發出了一個語句,那麼argument列就包含了這個命令的文本信息。 來看另外一個例子: command列中的connect表明是用戶一個鏈接到服務器的行爲,argument表明了具體的帳戶 再看一個例子: init db表明了用戶選擇的默認數據庫(經過輸入 use語句)。argument列說明了具體的數據庫名稱。 再看一個例子: quit 表明了用戶的退出行爲。若是quit行爲沒有具體command內容,那麼多是鏈接還處在打開狀態或者是其餘線程關閉了這個鏈接。 general_log 表 正如以前所說,general query log能夠寫入到數據庫表中,表名叫作 mysql.general_log。它包含如下幾列。 1 event_time:等效文件中的time列 2 user_host:執行語句的帳戶 3 thread_id:等效文件中的ID列 4 server_id 表明複製環境中的server id 5 command_type: 等效文件中的command 列 6 argument:等效文件中 argument列. 下面咱們展現一下表中的內容: 上例語法一樣適用於slow_log表。 mysql.general_log有幾個限制,最重要的限制就是不能被用戶經過dml語句修改。強行修改會報錯。這樣的表也不能被鎖住。FLUSH TABLE WITH READ LOCK 能夠安全執行的緣由是它僅鎖住了其餘全部表。在這些表上使用 LOCK TABLES會出現錯誤。 general_log表是一個CSV表(由逗號分割)。這張表容許用戶經過其餘第三方程序直接打開其對應的數據文件(general_log.csv 存放在數據文件中),由於CSV是一個被普遍支持的文件格式。但由於CSV不支持索引,所以會減慢sql查詢。 general_log表也能夠使用MYISAM格式,快是能快點,可是仍是不如直接寫入文件快。其餘的存儲引擎就不支持了。記住在你更改這張表的存儲引擎以前,你應該先關掉日誌,操做以下: 若是你不關心日誌表中舊的日誌內容,你能夠經過 TRUNCATE TABLE 命令進行清空。可是DML語句不行,也就是說你想刪除部份內容是不行的。所以,循環使用日誌是一個防止日誌表增加過大的方法。RENAME TABLE 命令就是一種行之有效的方法。可是在重命名錶以前,你得臨時關掉日誌。關閉方法如上。 像是 CHECK TABLE,OPTIMIZE TABLE,和REPAIR TABLE 命令都是支持的。修復操做速度會很慢,若是表損壞了,在修復以前,還不如重命名後重建一個新的,這樣也不會影響日誌記錄行爲。 若是你使用ALTER TABLE給轉換成MYISAM殷勤的日誌表加上索引,其相應的select操做就會更快,可是也會減慢insert操做,若是你使用日誌循環方法(就是那個重命名錶的),你能夠給這些歷史日誌表加上索引。索引建立速度依據歷史表大小有所不一樣,可能很是慢,並且還須要佔用必定空間,可是查詢速度會快不少。 使用general query log 排錯示例 如下兩個例子展現了經過SQL 表來展現 mariadb中可執行的交叉平臺的代碼。並不意味着在表中存放日誌就是個好方法,默認的方式是存放到文件,DBA們也應該仔細斟酌以後根據具體狀況作出決定。如以前error log 部分向咱們展現瞭如何使用linux命令來查看這些log文件。 第一個例子,假如你發現有人刪掉了一張還在使用的叫作 歷史訂單的表。並且還發現好在刪了還沒超過一星期。那麼第一件要作的事就是還原表。這個咱們在第八章備份和災難恢復再說。然而,這張表頗有可能會再次被刪掉,你固然不想這種事情再次發生。這極可能是一些權限或者是程序BUG。爲了找出具體緣由,好比誰刪了表,什麼時間。那麼這個SQL就能夠展現其具體內容: 如上代碼,第一個條件限定了event_time 必須不能超過1周,第二條件什麼也不作(第三個條件將會知足),這將會以一種很快的方式過濾掉不少記錄。第三個條件是最有意思的。你可能不知道服務器收到的具體字符串,好比它可能包含空格,數據庫名,或者表名兩側的引號,此時能夠使用%通配。只要包含你指定的內容的行都會返回,哦!別忘了單引號中是區分大小寫的。 因爲可能會返回到不少結果,雖然難以想象,但誰又說的準呢。所以,你應該這麼處理這些結果:最新的行必定是最近刪除表的那個語句,並且,你確定還頗有興趣看看究竟是誰還執行了這個類似的語句。咱們將把結果集排序後限定在20行。 緊隨第一個方法,接着咱們能夠這麼作:咱們發現id =100的鏈接在早上執行了drop table 語句。爲啥?這鏈接還執行過別的什麼沒有?咱們很想知道。除了你自己的好奇心,還由於查看執行歷史可能會幫助你找到網站應用中sql語句的bug。基於這些因素考慮,咱們執行以下命令: 以上就是使用general log 的常見用法,固然它還有更多靈活多變的方法提供更詳細的信息。好比全部客戶端一旦再也不須要鏈接,那麼就應該自動關閉以釋放內存,然而此處問題在於,mariadb依然會保持一些線程buffer和臨時MEMORY表,直到某一個鏈接斷開。這種狀況就形成了內存浪費。這時候能夠使用 general log來查看哪條鏈接沒有使用QUIT命令退出,也就是說查一下哪些鏈接沒有正確關閉。記住,若是一個鏈接如今關閉了,可是它從沒執行過QUIT命令,那麼這個鏈接極可能是被root用戶用kill命令關閉的。也有一些鏈接多是由於會話超時被關閉的(使用了@WAIT_TIMEOUT服務器變量)。換言之,應用程序建立了它們,卻沒關閉它們。所以它們很長一段時間都處在非活動期,浪費內存!例如咱們執行這樣的查詢 這個實驗須要建立一張新表,若是你建立了索引查詢會很是迅速。而後你能夠執行兩次後別退出,就在那裏耗着。檢索這張表的時候,輸出以下: 輸出很是容易理解。經過線程id來存儲。若是同一個線程id沒有QUIT命令,或者count(*)比匹配到CONNECT命令的數量還少。這就表明了線程沒有被順利關閉。除非服務器重啓,線程id在同一天中幾乎不可能出現重用的狀況,所以你count(*)的值多是1或者丟失。在以前例子中,11和12線程從未發起QUIT命令,所以咱們想知道這些線程怎麼了。 下面的命令返回了使用這些線程的帳戶: 好比這個例子,general_log左鏈接 tmp.g_log,找出g_log中那些線程id爲空的quit記錄。手快點,別在下次服務器重啓後再執行上面的查詢。具體帳戶以下: 如今咱們知道究竟是誰作了這些事,若是是應用程序調用的,那麼就把開發喊過來給他兩腳。 服務器日誌維護 全部的服務器日誌都須要維護,咱們將從FLUSH這個偶爾會用到的用來把最新信息寫入日誌的語句入手。而後咱們會討論如何搞循環日誌(包括文件格式和表格式)以釋放磁盤空間。 刷寫日誌 在當前操做以後或者操做備份以前,沒準你會用FLUSH把相關內容刷寫到日誌中。刷寫日誌意味着文件會被關閉而後從新打開,全部的緩存的信息都會在這個過程被寫入文件。就基於文件的日誌來講,FLUSH LOGS 語句就能夠完成。爲了刷寫全部日誌,執行如下操做: 下面一些帶參數的命令能夠只刷寫一種日誌: 默認狀況下,這些語句會被複制環境中的從端也複製過來。若是隻在主端執行,須要使用LOCAL關鍵字(或者NO_WRITE_TO_BINGLOG,同步),代碼以下: 注意,若是使用了general_log和slow_log表,這些命令對它們不起做用(指的local關鍵字)。刷寫全部表使用FLUSH TABLES 命令便可,這個命令會關閉數據文件而後從新打開他們。還會強制把緩存的變動寫入到文件中。然而沒有哪一種命令能只刷寫一張表,全部數據庫中全部的表都會被刷寫,命令以下: mysqladmin 工具也能夠刷寫日誌和表,命令以下: 基於文件的日誌循環 mariadb不會自動循環日誌 惟一例外的就是binary log,它會在到達指定大小的時循環。一樣,當刷寫binary log的時候,也會自動建立一個新文件。binary log自動循環咱們在第八章備份和災難恢復一章講解。其餘那些到達指定大小的日誌若是想要循環只能經過用戶本身週期性地去操做,RED HAT 企業版和其衍生的linux發行版提供了實現自動日誌循環的工具。 讓咱們來看看如何使用linux shell來重命名general log 文件吧。 首先你得得到ERROR文件的列表,大小以及一些相關數據。假如咱們把當前文件叫作 maria.log.01,對於再也不使用的歷史文件,經過後綴來區別(好比 02,03),示例以下: 若是顯示以上結果則意味着mariadb的配置文件中會包含這樣的選項: 如今你想要重命名這個文件,服務器正在運行,第一件須要作的事就是關閉日誌記錄功能 刪除最先歸檔的文件而後依次重命名其餘文件,以下: 接着開啓日誌記錄功能: 如今,刷寫日誌: 若是maria.log.01文件不存在,服務器會自動建立這個文件。保險起見,咱們使用如下命令檢查一切是否如預期: windows下,刪除文件命令是del,重命名是rename,得到當前目錄文件列表命令爲dir。所以對於windows平臺,正確命令應該是這樣的: 固然不該該在生產環境中手工進行這些操做,用這些腳本以前起碼都應該測試過確認沒問題再用。 RED HAT linux企業版裏面的完成日誌循環的命令叫作: mysql-log-rotate 基於表的日誌循環。 正如先前提到的,基於表來作日誌循環沒有問題,同時基於表的日誌查詢比較慢。爲了實現日誌循環,咱們須要建立存儲過程,這個過程經過事件調用,在本節後面有描述。 讓咱們看如下代碼而後討論它如何工做: 因爲全部的過程必須屬於一個數據庫,所以咱們建了一個叫作 「_」的數據庫用來存放程序。數據庫名字短點兒能讓你少敲代碼。 事件的第一個動做是刪除最老的日誌表。隨後,經過rename命令更改了日誌表的名字:general_log變成了general_log02.general_log02 變成了general_log03.因爲rename table命令是一個原子操做,所以若是一個重命名失敗了,那麼全部的重命名操做都會失敗。最後,過程使用like語句,建立了一張和general_log02結構同樣的 general_log表. general_log在過程的一開始被關掉。然而有可能general_log一開始就是關閉的。所以咱們把gerneral_log變量copy到一個臨時變量中,而後在程序的最後還原它。 這個過程很是簡單。如何寫好一個過程並不是本書範圍。可是要說的是一個好的過程是靈活多變而且帶錯誤校驗的。讀者在編寫過程當中能夠遵循如下幾個思路。 1 歸檔日誌的數量不該該固定,應該從表中讀取。所以,rename table命令不該該寫死,應該是由字符串拼出來而後經過 prepared 方式執行(聽起來很高大上,但其實用的很是多,由於sql自己並不靈活) 2 語句中的每一部分(old_name to new_name 部分) 應該判斷一下僅在原表存在的時候執行。由於沒有理由這張表不存在,咱們必須記住,若是找不到,那麼整個循環操做就會失敗。固然,drop table語句中也能夠用 if exists 子句判斷一下。 3 應該給用戶返回一個是否執行成功的結果,若是在事件中調用該程序,可能會致使出現錯誤(由於事件不能返回結果集);所以,你可能須要把結果記錄在一張表裏。 寫出這樣的過程代碼是很是有用的,1是更容易排錯,2是能夠隨時手動調用。然而,你可能但願週期性地自動執行,這時候,你須要寫一個叫作 例行程序的事件。(等同oracle 中job,自動任務,crontab等),代碼以下: 這樣的自動任務應該在服務器負載並不繁忙的時候執行,好比以前的例子,咱們把它放到週日和週一的0時執行。 SQL_ERROR_LOG 插件 error log中存放着SQL的錯誤,把這樣的錯誤日誌分開存放對於應用程序排錯是很是有用的。此時能夠經過mariadb 5.5中引進的插件SQL_ERROR_LOG 來完成。 插件默認不安裝,能夠經過下面命令安裝: //* 安裝一次便可,重啓無需再安*// mysql 用戶可能注意到了咱們使用了mariadb中的一個擴展語法——INSTALL 語句。它能夠安裝存放在sql_errlog中的全部庫,並不是只能安裝這種,只是在目前,咱們只有這一個庫。惟一的優點就是命令更短。固然也有不一樣的地方:不須要包含文件擴展名(.so或者.dll),這些由mariadb來操做。這使得命令獨立於系統存在。(mysql中應該也有相似的功能,我並非很瞭解mysql) 若是安裝了SQL_ERROR_LOG,系統就會多出幾個變量來控制日誌行爲。先讓咱們看看這些變量是啥,命令以下: 若是卸載了插件,對應的變量也就沒了。 先讓咱們描述一下你可能用到的變量: 1 sql_error_log_filename :log 文件的名字,存放於data文件夾,此變量只讀。 2 sql_error_log_rate: 表明了在錯誤寫入log文件以前能夠緩存多少個錯誤。1表明當即寫入。10表明了發生10個錯誤再一塊兒寫入。0表明關閉日誌。在sql錯誤頻發的系統中,調大這個值對磁盤壓力有很大的緩解。 3 sql_error_log_rotate:爲OFF,開啓爲ON(或者其餘容許的值)強制日誌循環。 4 sql_error_log_rotations:表明在日誌循環過程當中能夠保留多少個歷史歸檔文件。9表明能夠保留9個歸檔歷史文件(不含正在使用的)。此變量只讀。 5 sql_error_log_size_limit:單個日誌文件容許的最大致積(單位 b).一旦日誌達到了這個體積,就會使用新的日誌。此變量只讀。 循環操做在日誌到達sql_error_log_size_limit指定大小或用戶設置了sql_error_log_rotate時發生。舊文件和當前文件名字相同,只不事後綴名經過數字擴展以區分開。 強制循環對腳本或者存儲過程排錯是很是有用的,這使得咱們不用讀辣麼大的文件而只是找其中幾個錯誤就夠了。 註釋用他們所屬的語句記錄,然而,若是爲優化網絡流量,客戶端把語句發送到服務端以前再去清除提示是不可能的。除非使用 --comments 選項特殊指定,mysql命令行客戶端纔會剝離註釋。記錄註釋使搜索語句更加容易。例如,假設你不肯定給定的語句在某些狀況下是否產生了錯誤。你能夠添加惟一的ID到你的語句中,以下: 而後你就能搜索到包含你指定內容的行: SQL 錯誤日誌設計出來不是給程序而是給人讀的。好比這個例子: 如上,包含接收到語句時的日期,時間,發起語句的帳戶,以及發生的錯誤, 存儲過程排錯要點: mariadb 中的存儲過程排錯能夠說至關很差整。緣由不少,但最明顯的就是mariadb沒有任何原生的debug接口。有些排錯人員使用一些爛招式來模擬出排錯過程。好比分析過程代碼,往裏面加間斷點,或者跟蹤堆棧調用或者給他返回一些信息。這種招式會改動大量代碼,所以不大可靠。其餘一些排錯人員在內部執行代碼來實現排錯功能。然而他們不能在mariadb和mysql的任什麼時候候再現出準確的動做。尤爲是,若是你用的不一樣版本的數據庫,其實他們確定是有程序bug或者文檔中有錯誤的地方。固然,我不是特指誰,在座的各位軟件都有BUG。 爲了調試存儲過程,開發者須要使用一些小手段,好比經過在過程代碼中加入一些信息語句。可是記住,若是過程調試完畢,相應的語句必定得刪除或者註釋掉。 假如開發人員只是想知道if的分支語句是否執行了,那麼select 1 就足夠。好比這樣 大多數狀況下,在執行動態prepared 語句以前。開發者可能想經過查表中的一行或者變量來檢查值是否正確。校驗文本信息一般是比較靠譜的作法。好比這樣 然而,基於select的排錯方式僅適用於存儲過程,由於其餘程序(好比函數,觸發器,事件)不能返回結果集。就開發層面上講,一般是經過存儲過程實現功能。 對於事件比較簡單:能夠不加修改就把事件轉換爲過程。然而,事件一般無論執行是否成功均可以對錶寫入數據。這種機制在某些狀況下很是有用,好比說產生了錯誤,又什麼都沒給客戶端反饋。 對於函數還比較容易。可是函數比過程多了不少限制,因此最重要的是記住哪些功能不能在函數上用(好比,prepared語句),惟一須要修改的地方是過程不能返回值,所以RETURN語句須要轉換成select語句。 對於觸發器,轉換工做就很難了。由於觸發器能夠訪問記錄中的OLD值和NEW值。在一些簡單狀況下,轉換成過程須要的參數是個方便的解決方法。然而在複雜狀況下,這種方法容易出錯,由於值必須經過手動傳遞。比較好的解決方法是使用insert語句替代select語句。值不會返回給客戶端,可是它能夠寫入到debug表中(實際上是本身建立一張用來調試的表)。可是這種曲線救國的方法由於多了寫操做會增長代碼量。 經過 SQL_ERROR_LOG插件調試程序 SQL_ERROR_LOG是個用來調試程序至關有用的插件。例以下面的過程代碼: 上面這個過程很簡單,就是清空backup數據庫裏的表以後,copy一張須要備份的表到backup數據庫中。經過 TRUNCATE TABLE 和INSERT...SELECT 語句就能很容易的看出來。 然而這個過程卻隱含着不少問題,好比,backup表是否存在,源表是否存在,表結構是否改變了?或者有權限問題?其中任何問題發生都會致使SQL 錯誤。這種狀況下,執行會直接跳到DECLARE EXIT HANDLER 語句塊,除了抑制錯誤以外什麼也不作。這個語句塊看起來好像沒什麼用,然而在真實環境中,有好多理由去使用HANDLER語句塊。而且它會抑制一些錯誤(除非使用RESIGNAL語句).當在調試程序時,這就意味着錯誤不會返回給客戶端,而且開發者也不會注意到已經發生的錯誤。 在程序增長一個空的HANDLER是頗有用的。它能夠抑制一些你意料以內,而且又不會產生問題的錯誤或警告。比較有表明性的例子就是當存儲過程經過IF EXISTS語句試圖建立一張表的時候。若是表存在,就會產生一個note。然而在大多數狀況下,它不只沒用,並且還很煩人,好比你想在 EXIT handler中抑制note,那不行,程序依然會退出。在continue handler中,程序依然會正常執行,警告或錯誤會不明不白地忽略掉。雖然這多是所指望的行爲,但它也是一個潛在的問題:好比咱們使用SQLEXCEPTION這樣的通用類,handler就會抑制錯,這固然不是咱們指望的,這樣會使調試更麻煩。 使用show warnings 命令是一個快速查看錯誤的方法。可是這樣的語句只能用在過程,而不能用在不具備返回結果集能力的其餘程序中。 使用SQL_ERROR_LOG 插件是一個查看錯誤的好方案,好比: 執行這個過程的時候,咱們看不到有錯誤報出,可是咱們想確認是否產生了錯誤。若是咱們查看SQL error log的最新行,咱們能找到大概以下條目: 若是backup 表不存在: 若是原表結構改變: 若是原表已經被刪除: 若是每件事都作的正確,咱們固然看不到什麼錯誤。 總結: 本章主要講了日誌查閱,記錄以及理解mariadb中的錯誤。 咱們經過診斷區中的一行錯誤信息來得到系統運行的可用信息。咱們討論了診斷區填充清空的機制。以及獲取診斷區的一些命令,好比 show warnings,show errors 和 get diagnostics. 若是SQL_ERROR_LOG插件啓用,那麼SQL錯誤也能夠記錄到文件中。咱們還探討了如何使插件更高效工做。有些特性關乎到程序調試,這是一項比較有難度的任務。 general query log對於應用程序調試和找出問題所在也頗有用。當不產生任何錯誤信息的時候,它能夠跟蹤全部咱們發送到服務器的命令。這樣的日誌能夠被寫入文件或者general_log 表中。 SQL錯誤不是惟一可能發生的錯誤。error log包含了其餘類型的錯誤,包括服務器啓動失敗,或者插件加載,數據損毀問題。這些都會被記錄到文件中。 咱們還探討了 error log和general query log之間的格式。經過舉一些簡單的例子,使用linux命令行在日誌中找到咱們須要的條目。咱們還研究瞭如何使日誌循環以阻止單個日誌文件變得超大。 目前尚未具體分析mariadb中的全部日誌,關於其具體內容,在隨後的章節中會慢慢接觸,由於爲了找出使用mariadb高級技術過程當中產生的問題,那是必須的知識點。 在下一章中,咱們將會學習如何使用slow query log 來找到那些執行效率低下的sql語句。而且學習如何優化它們,使其執行更快。 第三章 查詢優化 本章將講解如何提高查詢性能。首先咱們會引入一個查找慢查詢的工具。一旦咱們找到了這樣的查詢語句,就須要找出慢的緣由。隨後會介紹mariadb中的索引,執行計劃(展現了查詢語句執行的過程)以及主要的幾種執行策略。 本章涵蓋一下幾點: 1 慢查詢日誌 2 percona toolkit的pt-query-digest工具 3 索引 4 表統計信息 5 執行計劃 6 mariadb優化要點 慢查詢日誌slow query log 慢查詢日誌主要是存儲那些執行時間特別長的sql語句。使用 slow_query_log 或者 --slow-query-log變量,設置爲1即開啓。設置爲0關閉。在啓動參數中不加任何參數默認表明1,即開啓慢查詢日誌。同時 slow_query_log變量可動態調整,服務器運行時可隨時開啓或關閉。 默認慢查詢日誌的名字爲服務器主機名跟隨-slow.log後綴。 和general query log日誌同樣,慢查詢日誌能夠是文件,表。經過服務器變量指定。可選參數:FILE,TABLE,NONE(會關閉慢查詢日誌和general query log)。能夠設置多個變量,用逗號隔開,NONE優先級最高,若有NONE則其他無效。 好比主機名是 HAL,那麼HAL-slow.log就是它的慢查詢日誌名。你也能夠經過slow_query_log_file變量或者--slow-query-file選項起個別的名字。在複製環境下推薦全部日誌的名字同樣,由於這樣能夠在全部服務器上執行一套腳本(我以爲做者這裏的意思是全部同種類型的日誌的名字在各個節點上保持一直。但種類不一樣的日誌仍是要經過名字區分開) 若是慢查詢日誌寫入表,那麼表名就是mysql.slow_log 第二章裏面咱們介紹了general_log表。slow_log表的原則和general_log表同樣。如以前所說,慢查詢日誌是用來記錄那些執行太慢的語句。可是何爲「慢」?這取決於服務器負載。正因如此,語句是否寫入慢查詢日誌是經過服務器一些變量來決定的。 首先不走索引的查詢確定要被記下,設置 log_queries_not_using_indexes(--log-queries-not-using-indexes啓動參數)變量爲1便可。此變量爲動態,可是做用範圍爲全局。 若是一個查詢走了索引,可是執行超時了,也有必要記錄一下,經過設置 long_query_time(--long_query_time啓動參數)變量爲非負數便可,單位爲秒。0表明不設超時時間。容許以微秒(最多六位十進制數)爲精度的十進制值。可是若是使用slow_log表,則小數位忽略。線程一旦得到了必要的鎖,則開始計時。也就是說,在等待其餘線程釋放鎖資源的這段時間不進入計算範圍。此變量爲動態,全局級,會話級均可。故能夠早執行更復雜查詢時設置更大的超時時間。 有些查詢自己存在一些潛在問題,關於這種狀況,能夠使用列表用來匹配各類狀況,那就是log_slow_filter變量。參數不少,能夠設置多個,用逗號隔開,如今咱們來看具體的變量值。 full_scan: 查詢走了全表掃描(等效log_queries_not_using_indexes) full_join: 全鏈接,使用join沒走索引的狀況。 filesort: 排序操做在內部臨時的內存表中完成。 filesort_on_disk:排序操做在臨時的磁盤文件上完成。 tmp_table: 查詢建立了臨時表 tmp_table_on_disk:查詢建立了臨時表,可是臨時表在磁盤上。 query_cache_miss:命中失敗,即須要的數據沒存在query cache中。 默認log_slow_filter包含以上全部變量,其動態,可配置於會話級和全局級。 即使某個查詢,既符合了 log_queries_not_using_indexes也知足了long_query_time(也就是既沒走索引又超時),min_examined_row_limit變量也能阻止它被寫入慢查詢日誌。單反返回行數小於這個變量設置行數的查詢都不會被記錄到慢查詢日誌中。0表明全部查詢都會被記錄。最大值取決於具體的計算機平臺,但確定是個超大的值。此變量爲動態,可配置於會話級和全局級。有什麼用呢?好比說某個查詢只返回了幾行,走索引徹底沒有任何優點(優化器根據統計信息裁決)。再好比說,有沒有這種狀況:返回行數不多,可是查詢很是耗時?有的,好比查詢很是複雜,包括排序,分組或者還調用了比較慢的函數。 在負載重的系統中記錄全部不走索引的查詢會給服務器帶來很大的壓力。所以就出現了這個參數 log_throttle_queries_not_using_indexes 系統變量。設置爲0表明不作限制,大於0的數用來表示每分鐘容許記錄到slow log的且未使用索引的SQL語句次數。當達到這個限制的,之後不走索引的查詢將再也不寫入慢查詢日誌,一分鐘後開始記錄最新的不走索引的查詢(也就是說中間的就給丟掉了),可是沒記錄的那些查詢會統計個總數寫進日誌。 全局動態變量 log_slow_admin_statements ,默認狀況下像帶有管理性的命令都是不寫慢查詢日誌的(好比 check table ,analyze table)。若是你設置爲1,那麼這樣的命令在知足條件的狀況下也會寫入慢查詢日誌。 在複製環境中,從端不會複製慢查詢日誌。由於能夠在主端找到(並且複製過來根本沒啥用)。一般來講,只有在從端直接執行查詢,纔有可能產生慢查詢日誌(這個不奇怪,好比我從端服務器性能甩主端幾條街,在主的慢查詢在我這邊算不上慢。從某方面來講能夠是衡量服務器性能的參數。尤爲在多源複製技術開發以後,從端服務器能夠做爲數據倉庫中心。譯者注)。可是能夠經過設置log_slow_slave_statement=1來改變這種策略,此變量爲動態全局。設置爲1以後,若是主端負載很高而從端很輕,爲優化起見,慢查詢日誌會記錄到從端而不是主端,想要這樣作,除了設置這個參數爲1以外,須要在主端關閉慢查詢日誌但在從端開啓。 爲了產生更少的慢查詢日誌內容,能夠使用 --log-short-format啓動選項(log-short-format配置參數)。此選項一樣會影響binary log。 與上面那個相對的參數叫作log_slow_verbosity。見名知意,它會在慢查詢日誌中添加一些額外的信息以供參閱,有不少參數,每種參數表明一類信息,若是想添加多種信息,參數用逗號隔開配置便可。參數以下: 1 microtime: 使用微秒爲單位。 2 query_plan:包含執行計劃相關信息 3 innodb: 記錄innodb數據 4 profiling: 開啓查詢分析 5 profiling_use_getrusage:記錄getrusage函數的結果 6 explain:輸出EXPLAN語句。 若是想使用 profiling和profiling_use_getrusage,那麼必須使用XtraDB引擎。此變量默認值爲 'query_plan'. 對於‘log_short——format’和‘log_slow_verbosity’參數,它們只能做用於文件類型的慢查詢日誌,對slow_log表不起做用. 總得來講,下面4個變量用來決定是否寫入慢查詢日誌 log_queries_not_using_indexes log_throttle_queries_not_using_indexes long_query_time log_slow_filter 下面兩個用來過濾上面決定寫入的條目 min_examined_row_limit log_slow_admin_staements 下面兩個用來決定什麼信息會被記錄(會由於記錄慢查詢內容多少產生相應的負載) log-short-format log_slow_verbosity 若是表中沒有記錄,或只有一行,則不會寫入慢查詢日誌。 基於文件的慢查詢日誌 服務器啓動時,相似下面這行會寫入慢查詢日誌 如今就讓咱們具體分析一下慢查詢日誌是如何寫入的。下面這個例子是在默認參數狀況的一個慢查詢條目 註釋行提供了關於查詢開銷的通常信息,意義以下: 1 Time:查詢語句執行的開始日期和時間。格式和以前咱們討論過的全部其餘日誌同樣 2 User@Host: 語句的執行人 3 Thread_id:鏈接的ID號,這個值和 information_schema和performance_schema表中的,以及經過connection_id()函數返回的值相同。在同一行中,還能看見Scheme參數指明的數據庫。 4 QC_hit:告訴咱們此查詢是否命中 注意看最後一個註釋行,query_time表明了語句執行時間,單位是秒,若是慢查詢日誌寫入的是文件,那麼精度能夠達到微秒。若是是寫入slow_log表,精度只能到秒。Lock_time 表明了該語句等待其餘線程釋放必要鎖的時間。若是是某個語句因爲須要等待其餘長時間運行的任務釋放鎖資源而在這個參數上花費了大量時間,一般狀況咱們不須要優化這個語句(不如去優化那個長時間運行的任務)。Rows_sent 表明了服務器返回給客戶端的行數,也就是結果集行數。Rows_examined :表明了這次查詢讀取到的行數。由於須要返回給客戶端須要的內容,一般須要服務器去分組,排序,鏈接,篩選等操做以後才能返回正確結果。若是沒有使用到足夠的索引或者根本就沒走索引,那麼這個值會大的不正常。不走索引會使得查詢語句開銷很是大。 而後,咱們找到要執行的語句以重複該過程,首先注意到 SET timestamp ,有時候是必要的(好比在where子句中使用了 current_timestamp()函數)。USE 語句一般只能在該鏈接第一次發生慢查詢行爲的時候被找到。固然,具體問題具體分析,有時候你不可能直接粘出其中的一些語句就能直接執行。好比若是使用了臨時表,用戶自定義變量,這些都是不肯定因素。但總得來講,是收到了慢查詢記錄。 若是使用了 log-short-format 啓動選項。那麼慢查詢信息就會更少,好比這樣: 這些結果是上面那個比較全的一個子集,其意義參照上面例子,不用再提。 若是使用了 log_slow_verbosity 變量,那麼慢查詢日誌中就有更詳細的執行計劃信息,執行計劃信息對優化sql很是有用,可是一般咱們都是手工去作執行計劃分析,不在慢查詢中使用。 SLOW_LOG 表 slow_log表包含的信息和慢查詢日誌文件的內容很是類似,但並不徹底相等。其包含了默認參數下的慢查詢日誌內容。內容以下: 左側是表列,右側爲文件參數,無特殊說明左右側等效 1 start_time Time 2 user_host User@Host 3 query_time Query_time 4 lock_time Lock_time 5 rows_sent Rows_sent 6 rows_examined Rows_examined 7 db Schema 8 last_insert_id和insert_id,包含關於AUTO_INCREMENT列的信息 9 server_id 列包含了複製環境下的server_id 10 sql_text 列包含了原始的查詢文本 11 thread_id Thread_id 來自 Percona Toolkit的 pt-query-digest pt-query-digest是Percona套件中的一個命令。這個命令能夠從慢查詢日誌,general_log,binary log和show processlist命令中得到具體的查詢信息。 想使用這個工具,須要安裝percona套件,通常linux發行版中都會包含這個套件。固然你能夠從 percona網站上下載 .deb或者.rpm包。mysql和mariadb均可以用。可是僅能在linux環境下,而且須要安裝Perl環境。 通常來講,咱們更傾向用這個命令來分析慢查詢日誌,由於慢查詢通常是嚴重問題所在。下面這個例子咱們立刻就演示,雖然到如今咱們還沒討論過慢查詢日誌,可是不要緊。用戶還能夠使用這個命令來分析general_log。這裏不會涉及pt-query_digest的每一個參數,咱們將經過例子來講明大體如何使用,好比: 假定慢查詢日誌存在,而且名字爲 slow_query。那麼pt-query-digest的輸出大體以下: 一般咱們關注的詳細信息是 查詢執行時間,鎖時間,掃描過的行和發送的行。對於每一項數據,都須要分析其最大值,最小值以及平均值——標準差將告訴咱們平均值有多大。和95%列相比,total列也很是重要。在本例中,5%的查詢花費了大量的時間。咱們能夠得知大概這些查詢應該是須要被優化的。在其餘狀況下,經過比較也能夠知道不少查詢都是欠優化的。由於具備低標準誤差的平均值是纔是理想結果。 95%的比率不是瞎說的; 儘管在示例中咱們使用了默認值,但能夠使用--limit選項進行更改。通常就使用默認值,而後根據須要不斷地調整,以找出佔用大量資源的查詢。(不明因此) 彙總數據以下: pt-query-digest命令會把問題最大的語句排在第一位。事實上,上面這個例子中。第一個查詢至關引人注目,它的相應時間很是大,並且還被調用了屢次。 幾乎不相關的語句會放在最後一行(跟問題最大的那個比較).這樣的數據叫作異常值(outliers):這些值不會用於計算平均值,由於它對於整個數據集合不具備表明性。使用 --outliers 選項能夠用來界定正常數據和異常數據。界定條件默認是查詢時間。可是也能夠改爲其餘條件,好比能夠指定一個語句被排除在異常值外的次數。 //* 關於--limit或者--outliers參數具體說明以及其餘選項,並不在本書範圍以內,詳細信息能夠去看percona的官方網站 *// 而後咱們針對上面那個問題最嚴重的語句來一個單獨的報告,看看具體內容: (沒有說明,直接本節結束了!) 索引 在討論mariadb如何使用執行計劃以前,不得不先討論索引。 索引能夠建立在一列或者多列上,具備順序相關性。若是是對字符串的列加索引,能夠根據字符串前綴來定義(具體數據最左邊的部分,好比對姓張的,姓王的,姓李的)。對於TEXT和BLOB列,索引強制存在。 //* 極少狀況下僅使用一個前綴索引就能加速整個查詢,然而,基於節省磁盤空間考慮(索引也會佔用磁盤空間)。若是在where子句中只匹配相關列的最左邊部分,咱們就能夠選擇使用局部索引。好比姓王姓李這種列,每個字符或者每組字符都有其特殊意義,使用局部索引能夠在節省磁盤空間的同時提高查詢速度。*// 本書涉及兩種索引:BTREE和HASH.至於像用於幾何運算的RTREE,用於全文查找的FULLTEXT全文索引都不在本書範圍以內。 至於HASH索引,它只能用於 =和<=> 操做符。不能用於排序和分組,這是由索引類型決定的,所以本書全部例子都是針對BTREE來說解,HASH索引不會再提。 BTREE的應用場景很是豐富,能夠使用許多操做符,好比<,<=,=>,>,like,between,IN.還能夠用於排序和分組。 所以,任何語句均可以從創建了B樹索引的列中得到速度提高。HASH就只能用在精確匹配索引條目當中了。對於這種查詢,HASH索引比B樹更快。可是記住,根據不一樣的查詢類型,有些索引可能會被忽略。若是隻能走B樹索引,也無所謂了,一般這不算性能問題。 B樹索引是不少存儲引擎默認的索引類型,然而MEMORY是個例外,它用來準確匹配數據,所以默認使用HASH索引。若是HASH不適合咱們的查詢需求,那麼須要專門配置一個B樹索引。在隨後的 存儲引擎和索引一節中。InnoDB能夠選擇使用自適應算法來靜默地將BTREE索引轉換爲HASH索引。固然,若是後者更適用於當前服務器負載的話。 像以前提到的最左側的局部索引在mariadb中是能夠使用的,好比某個叫col1的列,以下查詢會在這種索引中得到速度提高 固然,若是我匹配的事字符串的最右側,中間部分,或者僅是字符串的一部分,那麼這種狀況將不會使用該索引,好比這樣: 同理,若是一個索引關聯了多個列,那麼它僅能爲最左側的查詢提供速度提高。但不能加速對最左側的最左部分的模糊查詢。好比這樣,索引創建在 col1 和col2兩列上: 這樣能夠使用索引 這樣就不行了。 即使子句中的列順序不符合索引順序,對於order by,group by 這樣的子句均可以使用到索引,可是,這樣會產生二次排序,數據須要先拷貝到臨時表或者文件中,然而再排序。這種I/O量簡直能夠說是性能殺手,應該極力避免。好比下面這個查詢不會產生二次排序: 可是下面這個就會有二次排序了 若是一個查詢不須要訪問數據表而直接經過索引返回值,那麼它的性能提高很是可觀,這種狀況主要由於 select語句只返回索引列,而且其餘全部子句均可以今後索引中獲益。那麼這種狀況叫作 覆蓋索引。(說的比較模糊,仍是建議去百度看大神貼 https://my.oschina.net/BearCatYN/blog/476748) 表統計信息 即使查詢能夠使用索引,優化器依然會決定是否使用索引或全表掃描。通常原則就是比較走索引會不會減小讀表操做。具體取決於索引的基數,若是是惟一列(文中所說是行中不一樣的值的數量和行號同樣),那麼使用索引帶來的提高很是大,可是若是行中數據相同的不少,好比說性別啊,地區啊或者一些布爾值。使用索引會很是慢。「可選擇性」是衡量where子句中使用索引可否帶來性能提高的重要指標。 是否使用索引,優化器會基於幾個因素考慮,好比上面提到的索引基數,索引長度,和表數據量。好比若是表數據量不多,那麼走索引查詢還不如全表掃描來的快。有個問題就是mariadb只能知道基數的估算值,無法知道準確值。可是也基本很準確了,只是有以後和真實數據不大同步。經過基數就能使優化器決定究竟是走索引仍是走全表掃描。固然你也能夠手動從新統計表的索引基數——ANALYZE TABLE命令。其估算索引基數能夠經過SHOW INDEX語句顯示出來.索引統計信息能夠經過存儲引擎或者服務器進行收集。好比說除了惟一索引以外,確定有某列或某幾列裏面的幾行記錄是相等的,若是是有索引前綴的話,那就更明顯了。(即使在惟一索引中,自增列前綴好比這樣的 200000,200001,200002,前綴20000%算作相同)。那麼這樣出現的相同值的,歸爲一組,(若是經過索引定位到多個行,那麼只能對這些行進行表讀了。)。其中有三個參數,主要是對null值作的調整,分別是 innodb_stats_method,aria_stats_method和myisam_stats_method。它們可選參數值的意義相同。分別解釋一下:nulls_equal:全部null值視爲一組。null不多的話比較好 ;nulls_unequel:全部null視爲不一樣的組,適合於null值比較多,缺點是,好比我其餘相同值的組特別多,某組有10000個相同值,另外一組有6000個相同值,可是這時候null值也很是多。這就致使出現了不少只有1個相同值的不少組(都是null,可是是不一樣組)。直接把平均數拉低。可能出現濫用索引;nulls_ignored:直接忽略null值 innodb和myisam默認爲 nulls_equal,aria默認爲 nulls_unequal. innodb有一個叫作 @@innodb_stats_on_metadata的變量。默認是關閉的,設置爲1後。在每次用戶執行SHOW KEYS或者訪問information_schema數據庫中的一些表的時候會自動收集統計信息。若是對應的表很大,將會花費很長時間 。 從 mariadb10以來,服務器自己也能夠收集統計信息。這些數據不只包括索引列,甚至非索引列也能夠收集。主要問題就是這個特性在每次統計一張表的數據的時候都會產生全表掃描。存儲引擎收集方式默認是關閉的(Engine-independent statistics are disabled by default),也能夠經過服務器變量 @@user_stat_tables來調整。never表明優化器不使用統計數據。complementary表示存儲引擎提供不了的統計數據由服務器來收集。Preferably表示儘量服務器來收集統計信息。實在收集不了的用存儲引擎收集(其實這個參數就是權衡兩種方式,作一個優先級排序) 存儲引擎和索引 對於innodb表,它老是有個聚簇索引。該索引的每個葉子節點都惟一表示表中的每一行(原文說的實在模糊,我解釋一下:就是索引的葉子節點其實就是表中的一行數據,這樣的索引只能創建在惟一列上,若是沒有這種列,使用自增列,對於oracle來講,參照索引組織表,一個意思。)除了這個索引,還有一種叫作二級索引的,它的葉子節點包含了索引列的值以及對應主鍵(或者惟一列)的值。只有聚簇索引纔有指向表中具體行位置的指針。這種結構比myisam的複雜得多。對於myisam,它的索引就像常規索引同樣,包含列的值和具體的位置。對innodb,經過主鍵列搜索比經過其餘列搜索更快(經過二級索引查找會二次訪問聚簇索引) innodb使用主鍵來創建聚簇索引,若是沒有主鍵,那麼使用惟一索引,若是連惟一索引都沒有,那麼就使用6bytes的不可見列。這樣的聚簇索引意味着會比經過主鍵列創建的聚簇索引有更多的鎖衝突。因此對於innodb來講,最好都有主鍵列。 auto_increment值有一種鎖機制來保證多個併發鏈接訪問同一值。鎖的工做機制取決於innodb_autoinc_lock_mode系統變量。其參數以下: 0:只在老版本的innodb中可用,表明若是有insert行爲,則鎖表,直到事物結束。 1:在批量insert和LOAD DATA INFILE時,依舊會鎖表,若是是單行insert,則會有一個輕量鎖(行鎖),基於語句的複製環境中更安全 2:此值不鎖表,若是是基於語句的複製,則不安全,若是是基於行的複製,沒問題,在 Galera集羣中是強制的。 若是innodb_adaptive_hash_index服務器變量設置爲1(默認值),那麼innodb能夠自動把BTREE索引轉換成HASH索引,反過來也行。有什麼用呢?若是此時數據正好在buffer pool中,而where子句中使用的「=」操做符。那麼hash索引的速度比B數索引更快。(自適應)。爲了決定使用何種索引,innodb會收集關於表被如何使用的統計信息。增長 innodb_adaptive_max_sleep_delay系統變量能夠減小這種收集操做,對負載繁重的系統頗有用。 對於aria和myisam,索引存儲他們選擇的每一列的最小值最大值。所以,select語句不須要任何操做選項,就能夠返回最大最小值。 索引的限制(包括每張表能夠建多少索引,一個索引能夠包含多少列,索引高度,前綴長度等等)具體取決於存儲引擎,但一般來講足夠用。 有些存儲引擎,好比CSV,根本不支持索引。 EXPLAN 漫談 EXPLAN工具是用來理解mariadb服務器內部如何執行一條SQL語句的工具。在mariadb10版本中,不光能夠用來查看select語句,對於update和delete一樣適用。語法以下: EXTENDED選項可增長一列輸出,而且生成一個NOTE(用 show warnings命令可查),包含了被優化器重寫過的sql語句。 mariadb10中,還有一個命令能夠使用: 這個命令能夠用來查看運行中的sql語句的執行計劃,好比有個任務跑了很長時間,咱們想知道爲啥,那麼能夠使用這個命令來看看運行中的任務的執行計劃是什麼樣的。thread_id指的是運行中的線程id,經過show processlist能夠獲取。 下面展現如何使用EXPLAIN語句,以及查看優化器如何對SQL進行重寫的(EXTENDED選項) 若是任務執行完畢以後才經過 show explain for thread_id來查看執行計劃,那麼就會收到一個錯誤,以下: EXPLAIN適用於select,update和delete,對insert也能用,可是沒啥有用信息(我試了一下,大概是這樣的) 理解EXPLAIN輸出內容 本節咱們將會分析一下EXPLAIN的輸出內容,同時還會討論語句是如何執行的以及mariadb中的最重要的優化策略。 對於 JOIN和UNION查詢,EXPLAIN會把每一個小的SELECT分紅兩行數據,其可能包含如下內容: id:每行的惟一標識 select_type:SELECT語句的類型 table:SELECT語句讀到的表 partitions:若是是分區表會有具體的分區信息 type:鏈接(JOIN)的類型 possible_keys:顯示查詢能夠使用哪些索引,這個列表在優化過程早期建立,可能列出的索引對後續優化沒什麼用 key:mysql決定採用哪一個索引來訪問表,若是爲NULL,則爲全表掃描 key_len:mysql使用的索引長度(掃描過的索引大小) ref:顯示了鏈接兩張表的那個列(只有當使用非惟一索引或者惟一索引的非惟一前綴纔有) rows:估算掃描過的行數 filtered:顯示因爲where條件過濾掉的返回結果的百分比(僅在 explain extended時顯示) extra:額外信息 (關於id列,原文是每行的標識,可是試驗發現,它是表明了單條語句的標識,好比我select使用了join,那麼計劃會分紅兩行,可是id是相同的,代表是同一個查詢,好比) 簡單的SELECT語句樣例 如今先使用select開始練習一下,咱們先建立一張表: 建立表以後,咱們執行以下命令: type的值爲index,表明了查詢使用了索引。具體索引經過key列展現出來爲 idx_birth_sex. possible_keys列爲空。查詢的列所有都有索引,所以使用了索引覆蓋,經過Extra就能看出來。 idx_birth索引沒有被使用,由於在group by子句中這個索引沒有包含全部列。可是idx_birth包含的列idx_birth_sex索引中都有。所以能夠使用索引覆蓋。記住,索引會影響寫入性能,基於優化策略考慮,創建索引要適度。 內部臨時表或者文件 有時mariadb爲執行語句須要建立一個臨時表。若是讀取數數據須要進行不止一次讀操做,那麼把數據複製到臨時表,在複製結束時會釋放表鎖。然而,若是複製的數據量太大,那麼會形成巨大的開銷。應儘可能避免。 內部臨時表會用在如下幾種狀況: 1 對於聚合數據的視圖,或使用TEMPTABLE算法定義的視圖 2 union操做 3 同時使用了order by 和group by 而且順序不一樣 4 在JOIN查詢中,不是第一個讀到的表的字段使用了order by或者 group by 5 distinct 和order by 同時出現 6 當子查詢或者派生表須要物化的時候 若是使用了臨時表,則在explain輸出的extra列會顯示 using filesort或者 using temporary 默認,臨時表使用aria存儲引擎,以提高group by 和distinct操做的速度。若是設置參數 aria_used_for_temp_tables=0則臨時表使用myisam引擎。這麼設置是基於aria引擎可能有BUG或者aria不能知足咱們的查詢要求考量,可是基本不大可能。 一般臨時表活躍在內存中,若是臨時表大小超過了 tmp_table_size或者max_heap_table_size服務器變量指定的大小,則臨時表會寫入磁盤。如下幾種狀況總會致使臨時表存儲到磁盤中。 1 讀取列涉及TEXT或BLOB類型 2 當group by或者distinct子句包含的列超過了512字節(非字符)。此規則一樣適用於union distinct 3 union all 操做 UNION 查詢: UNION查詢和簡單的select語句很不同。union中的select語句會單獨進行優化。如今來看一下執行計劃中的union是怎麼樣的 輸出如上,第一行primary,表明了第一個select語句。隨後第二行是UNION,此類型用於全部後續查詢。最後的UNION RESULT表明了真正的UNION操做 簡單索引訪問方式 mariadb有幾種索引訪問方式,其中之一就是range,其在索引中定位了精確的區間。好比下面兩個例子使用了範圍索引: type列告訴咱們使用了範圍索引。HASH索引也能夠用在範圍掃描中,可是因爲只支持=和IN操做符,因此你得把具體的值寫成列表好比IN (‘1’,‘2’,‘3’,‘4’,‘5’)。 另外一種索引訪問方法是 index_merge,出如今範圍掃描可是使用了不止一個索引的時候,這時候type列就會出現index_merge。 JOIN子句的索引優化 當經過JOIN進行多表鏈接的時候,表的鏈接順序是很重要的。例如,若是一張表有10000行,另外一張只有1000行,那麼先讀小表是比較好的方案。若是where子句還能排除一些行,那麼到更大表中進行匹配的行就會更少。這個表的鏈接順序和出如今執行計劃中的順序是徹底同樣的。 基於存儲引擎搜索的統計數據能夠幫助優化器選擇最優的順序,mariadb存儲了索引列和非索引列的數據分佈直方圖。所以,有時候優化器瞭解具體數據的可選擇性,好比qty=1可能比qty=100更具備選擇性。 也能夠強制mariadb經過指定順序去讀表,經過使用STRAIGHT_JOIN便可。 優化子查詢 依據相關理論,在where條件中包含一個子查詢的select語句叫作半鏈接。一般這種查詢性能不如JOIN好,JOIN僅從表中提取須要的列。例如若是咱們想知道當前分類中產品的平均價格,那麼下面這種語法就顯得很直觀: 經過JOIN也能夠返回一樣的結果 mariadb有一種優化策略叫作 table pullout,會把半鏈接轉換成完整JOIN。若是優化器不這麼作,查詢速度會很慢。table pullout在mariadb5.3以前並不支持。在當前的mariadb版本中,若是子查詢很慢。咱們應該查看一下優化器是否進行了table pullout。若是沒有,那麼咱們就應該本身完成。 另外一個重要的優化策略叫作FirstMatch。用在IN子查詢中。一旦記錄找到,那麼子查詢就可能中止(即使子查詢中有多個結果都符合也只取第一個匹配到的值)。若是使用了這種優化策略,那麼在EXPLAIN中的extra列就能夠找到 FirstMatch(tableNumber)字樣 LooseScan 是專門用在IN子查詢中的策略。好比這樣 子查詢從satellite表中返回全部的country_code。其中不少國家代碼多是相同的。那麼優化器就會把這樣的值分組並和左側表進行鏈接。避免出現重複結果。若是使用了這種策略,EXPLAIN的extra字段中會顯示 LooseScan字樣 在老版本的mariadb和mysql中,會對全部派生表(from 中使用的子查詢)進行物化。速度很慢,尤爲是物化數據量很大的時候。Maraidb不論什麼時候都應該儘可能避免。在這種狀況下,將轉換查詢以讀取相同的數據,而不使用任何派生表。若是優化沒法完成,那麼EXPLAIN的Extra列會顯示 Using temporary。即使在這種狀況下,在物化表上添加一個鍵仍是能夠起一些優化做用的。 總結: 本章中,涉及了發現慢查詢的步驟以及優化方法。 首先咱們分析瞭如何配置可以篩出須要調優的慢查詢。和用來定義何爲慢查詢的標準。還討論了pt-query-digest工具。 咱們討論了mariadb的索引。能在一次查詢中使用到必須的索引,對於優化來講很是重要。隨後咱們還討論了mariadb10中很是重要的特性——存儲引擎級的統計數據。它會收集索引和非索引列。這能夠幫助優化器選擇一個合適的執行計劃。 而後。咱們說到了EXPLAIN工具。這個工具展現了mariadb執行sql的策略和具體過程根據EXPLAIN的結果和執行計劃相關執行,咱們能調整索引和查詢來達到優化sql的目的。 固然,在併發環境中,僅從一個角度優化查詢遠遠不夠,下一張咱們將會討論事物會話見的衝突,鎖以及因爲隔離級別致使的負載問題。 (注: 關於此處提到的 統計信息不止存儲引擎能夠收集,服務器也能夠收集。此處的服務器應該指的是除去引擎以外的實例了。我並未找到相關資料。而且也爲找到文中所說的 @@user_stat_tables. 可是我找到了 use_stat_tables; 因此此處內容請各位讀者自行斟酌。 關於做者上面本身提到的,好像是隻有服務器收集統計數據的方式才能收集非索引列,不知道下面又怎麼變成存儲引擎方式收集的能夠收集非索引列了。「這種數據」,「這種方式收集的數據」怎麼翻譯都以爲是在說服務器收集數據方式。 後來我在mariadb的官文中找到了解釋。地址以下: https://mariadb.com/kb/en/mariadb/engine-independent-table-statistics/ 官文中並未明確說起 「server collect」這種話,所以是否服務器能夠收集統計信息並未明肯定論。只是說在mysql庫中增長了 table_stats,column_stats,index_stats 這三張表。你能夠經過修改其中的數據來改變具體的統計信息。優化器也能根據 use_stat_tables的參數來決定從哪裏讀取統計信息。 即便用 Engine-independent表,it can control of the statistics)。 第四章 事物和鎖 (都能看懂吧,看得懂我就不譯了) 所以,事物是保證數據完整的重要特性。保證了當操做失敗的時候,數據不會處於不一致的狀態。好比管理一個電子商務網站,其中一張存放訂單,其餘存放可用產品和數量。當一名顧客買了一個產品的時候,那麼訂單表必然加一,對應的產品數量必須減小。這些操做必須在同一事物中完成。只有這樣才能保證服務器在訂單記錄寫入以後,產品數量減小以前崩潰後,整個數據不會生效。若是全部的操做都成功了,這才能夠說是一個事物被完整地執行了。 可是,事物還有另外一個重要特性——隔離級別。隔離級別有不少種,每種隔離級別表明了不一樣的隔離類型。不管如何,其中心思想是一個事物型操做不會干擾到另外一個事物。讓咱們回到電子商務網站那個例子。當顧客買下一個產品的時候,應用程序會校驗客戶購買的產品是否能夠售出,隨後會減小對應商品的數量。這樣的操做會設計在一個事物中,以免發生相似這樣的問題:若是兩名顧客同時買一樣的產品,其中一名顧客開始了一個事物,而且鎖住了她想要買的那個產品的相關的表的行記錄。第二名顧客只能等到第一個事物結束後才能下單。只有這樣,在第一個顧客買了最後一個庫存產品後,第二個顧客纔不會買到「虛幻」產品。mariadb中,事物是由存儲引擎來控制的,好比innodb,tokudb和spider(mysql也是) 存儲引擎用來保證數據一致性的基本機制就是鎖,咱們將會在本章涉及。同時也會討論關於ALTER TABLE這個能把大表一鎖就鎖很久的命令。 INNODB 鎖 鎖是一種數據結構,由用戶獲取並關聯到相關資源。只要用戶持有了鎖,那麼別的用戶就不能修改鎖持有者對應的資源,取決於具體的鎖類型,可能讀,可能讀都不行。通常來講,併發操做會進行隊列處理。InnoDB能夠鎖住行和整個表來防止出如今併發操做下可能出現的數據混亂問題。 爲了理解Innodb鎖是如何工做的,有必要先去學習一下併發事物是怎麼回事。這也會幫助咱們診斷和處理問題,好比死鎖現象。 當事物須要訪問一行的時候該行就會被鎖住,鎖會被事物一直持有,直到事物發起了commit或者rolls back操做。固然,等待鎖釋放也是有時間限制的,具體取決於服務器變量 innodb_lock_wait_timeout,單位爲秒。默認50,一般能夠配置稍微少一點。若是有超時狀況,事物會被強行中斷並拋出錯誤,好比: 鎖模型 Innodb主要有兩種鎖模型:共享鎖和排他鎖。共享鎖阻止其餘鏈接進行寫操做可是能夠讀。排他鎖甚至連讀都禁止。隔離級別決定了其餘鏈接是否能夠寫那行(正持有鎖的行)。共享鎖在讀以前獲取,排它鎖在寫以前獲取。不論事物是想得到共享鎖仍是排他鎖以前,都須要先得到一個意向共享鎖或意向排他鎖。總而言之呢,一個意向鎖表明了一個事物正在等待獲取一個共享或者排他鎖,而且阻止兩個事物對同一行記錄持有鎖。 共享和排他鎖通常表示爲 S和X。對應的意向鎖表示爲 IS和IX 若是一條記錄上有一個鎖的話,那麼對於另外一個不相容的鎖,則沒法同時持有,若是有這樣的鎖,那麼鏈接就會一直掛起。下面這張表展現了不一樣鎖模型之間的兼容狀況。 鎖類型 innodb支持行鎖和表鎖 //* 表級鎖會鎖住整個表,經過發起LOCK TABLES命令便可,可是innodb中最好不要這麼幹,而且默認也是關閉的,若是你想這麼搞,那麼設置服務器變量 innodb_table_locks=ON便可。LOCK TABLES命令設計出來主要是用於非事物表的,好比 Aria和Myisam。由於只能鎖住整個表而不能單獨鎖住行,致使性能不好。須要說明的是 information_schema庫中那些InnoDB-之類的表存儲了鎖的相關信息。可是若是是經過LOCK TABLES命令產生的鎖,則不會記錄在內。*// 行級鎖能夠鎖住一行或更多行。innodb有如下幾種鎖:記錄鎖,區間鎖以及next-key鎖. 1 所謂記錄鎖就是針對單行記錄而言。若是表上沒有任何索引,那麼鎖就會關聯到聚簇索引上(以前章節描述過) 2 next-key 會鎖住涉及到的索引記錄和以前的全部記錄。這能夠阻止其餘鏈接插入和修改當前事物正在處理的行。next-key鎖用在 REPEATABLE READ(重複讀)隔離級別中(此處講的不全,建議百度一下相關例子。另外記住innodb的特色:索引即表) 3 區間鎖會鎖住一個記錄集。這個「集」能夠是一條,多條甚至是空的記錄。這種鎖不會用於惟一索引列,除非索引由多列組成。 一個特殊的區間鎖是插入區間鎖。在插入新行以前獲取,若是此時另外一個鏈接嘗試在相同索引值的位置插入一行,則它會掛起直到當前事物提交或回滾。 區間鎖不會用在READ COMMITTED(讀提交)隔離級別中。 診斷鎖 鎖雖然能夠保證數據的一致性,但同時也會出現性能問題。每一個鎖都會致使一個或更多個會話處於等待狀態,拖慢應用程序。若是某個會話長時間處於等待狀態,那麼咱們必須找出緣由並解決。 SHOW ENGINE INNODB STATUS是查看關於鎖信息的命令。雖然輸出很長,可是很容易理解,而且還分紅了幾小塊,其中有一部分是 TRANSACTIONS ,內容以下: 對於每一個事物,都有一個事物ID。如上顯示的,最新的事物活躍了9秒。線程ID是4,這對於排錯很是重要,經過SHOW PROCESSLIST命令能看到線程4正在作什麼。操做系統的線程ID也被展現了出來,不過是以16進制格式,可是能夠經過UNHEX()函數進行轉換,而且咱們還知道有一行被鎖了。 在往上看還有一個事物,活動了3秒,在對一個有鎖行插入的時候阻塞了3秒。 若是想看詳細地信息,能夠經過 information_schema庫中的INNODB_LOCKS表來查看。須要記住,這張表只包含事物中出現的阻塞信息,表由如下幾列組成 1 LOCK_ID:就是個id而已,區分不一樣鎖 2 LOCK_TRX_ID:等效 SHOW ENGINE INNODB STATUS 中的事物ID 3 LOCK_MODE 可能值:S,X,IS,IX;對於區間鎖:S_GAP,X_GAP,IS_GAP,IX_GAP;對於自增鎖 AUTO_INC。 4 LOCK_TYPE:鎖屬於行鎖仍是表鎖 5 LOCK_TABLE:那些表上有鎖。具體表名由數據庫名和表名組成。 6 LOCK_INDEX:對於記錄鎖,其展現了鎖住的索引名稱。 7 LOCK_SPACE:對於記錄鎖,展現了表空間和鎖的關聯狀況。經過INNODB_SYS_TABLESPACES表能夠查看具體表到底屬於哪一個表空間。 8 LOCK_PAGE: 對於記錄鎖,表明了頁號 9 LOCK_REC:對於記錄鎖,表明頁中的記錄號 10 LOCK_DATA:對於記錄鎖,表明被鎖住的記錄的聚簇索引值。 INNODB_LOCK_WAITS表展現了哪些事物正在等待獲取鎖,哪些事物正持有別的事物正須要的鎖。其列含義以下: 1 REQUESTING_TRX_ID:等待中的事物ID 2 REQUESTED_LOCK_ID :請求鎖的ID 3 BLOCKING_TRX_ID:阻塞的事物ID 4 BLOCKING_LOCK_ID:阻塞了其餘須要獲取鎖的事物的鎖的ID(注意是鎖的ID) INNODB_TRX表包含了活動事物的信息 下面這個例子經過把INNODB_LOCKS和INNODB_LOCK_WAITS錶鏈接查詢,來查看全部阻塞了其餘事物的事物,說白了就是發生阻塞的鎖的信息。 須要明確的是 information_schema表中關於INNODB相關的表不會包含經過LOCK TABLES命令產生的鎖的信息。由於這種鎖是經過mariadb服務器自己發起的,並不是存儲引擎。 SQL語句產生的鎖 update 和delete語句會鎖住全部掃描過的索引記錄,甚至包括那些不知足where條件的。讀鎖能夠釋放掉那些不知足where條件的鎖,可是有時候也不行。 //* 當修改數據的語句沒有使用任何索引的時候,那麼表上的全部行都會被鎖住。這種狀況在使用select for update的時候也會發生 *// update和delete語句須要對掃描過的每行都得到一個排他next-key鎖。 Insert會在索引中須要插入的位置得到一個插入區間鎖。插入不一樣值的事物不須要互相等待。在插入操做以後,一個排他記錄鎖會鎖在新行上,直到事物結束。若是發生重複錯誤,一般事務不回滾,並將共享記錄鎖定在現有記錄上。若是使用了 ON DUPLICATE KEY 子句,那麼排他next-key鎖就會鎖定在現有記錄上。 insert ....select 語句和單純的insert語句很像,只是沒有插入區間鎖。在 read committed 隔離級別中,語句的select部分會執行一致性讀,與此同時,共享 next-key鎖會鎖定讀過的行 若是有外鍵,還須要讀一些行來保證複合完整性約束,在讀到的每一行,都會有一個共享記錄鎖。 一致性讀 本節咱們將會講解事物的一致性讀以及innodb如何來保證一致性。一致性查詢取決於具體的隔離級別,START TRANSACTION的WITH CONSISTENT SNAPSHOT選項,LOCK IN SHARE MODE或者SELECT FOR UPDATE語句.不一樣的一致性讀參數對應用程序工做的可靠性和提升併發性上有着很重要的影響 non-repeatable 讀 所謂non-repeatable讀,打個比方,頗有可能在同一個事物中執行兩次查詢可是獲得的結果卻不同,然而這個事物又沒修改什麼數據。這種狀況會發生一是由於事物之間沒有獲得足夠的隔離,二是兩次查詢中間有其餘鏈接修改了數據。 固然,這樣能夠提升應用程序的併發性,可是開發人員必須意識到會有這種狀況出現,而且決定是否容許這樣的問題存在。(通常來講都是儘可能避免) read repeatable 是由一致性讀和讀鎖組成的,Next-key鎖 保證在查詢後在給定範圍內插入新值的保護。這些機制都會在本節的隨後部分講解。 Phantom Row(幻讀) next-key避免了幻讀的出現。啥?舉個例子,好比一個事物在非索引列發起了一個範圍查詢,像這樣 where column between 10 and 20. ,而後這個查詢返回了 10,15,20三個值。此時,另外一個鏈接插入了一個13.若是第一個鏈接又執行一次這個查詢,那麼它就能看到 13,這就是幻讀。 若是是索引列,innodb 使用了next-key鎖。第二個鏈接能夠不用等第一個鏈接結束就能夠插入新值。可是新值對第一個鏈接是不可見的,這就在很好的保證了事物間的隔離。 再舉個栗子 首先打開mysql客戶端。建表,帶索引,插入 1,3,5 隨後開始事物(repeatable read隔離級別),而且檢索全部值 >=3的數據。 下面開始展現next-key鎖 如今打開另外一個mysql客戶端鏈接,自動提交模式下。咱們插入新值:4.當即獲得服務器的反饋。 如今回到第一個鏈接上,再查一遍,觀察結果,而後提交,再查一遍結果,能夠看到兩次結果的區別 就如以前說的那樣,提交以前,新行對第一個事物是不可見的。所以數據在一個事物中才能保持一致性。可是提交後,新行便可見。 一致性讀 一致性讀指的是在當前會話中從表中讀取一致的數據。當一張表被當前事物第一次訪問到的時候就會建立一個快照。快照表明瞭當前表的當前時間點的映像。其餘鏈接對錶作的更改不會影響到快照,即使是commit操做。若是當前事物在這張表上作了DML操做,好比insert一行。那麼也僅僅是修改了本身的快照。其餘鏈接也不會意識到這種變動。當發出commit命令以後,快照的改變就會映射到真實表上而且對其餘鏈接可見。(注意這裏是其餘鏈接可見,不表明當時必定能看見。這和當前鏈接看不到其餘鏈接提交的改變是同樣的道理)。而其餘鏈接對錶作的變動當前鏈接再次查詢的時候就也能看見。 //* 請注意,這種技術會致使當前事務查看從未存在的表版本。要使當前鏈接瞭解其餘鏈接所作的最新更改,可能須要COMMIT事務並啓動新的事務。 *// 一致性讀這種情景是在 repeatable-read隔離界別經過 start transaction with cosistent snapshot發起。也能夠是在 read committed 的select語句中出現。可是記住,即使是在同一個事物中,每一個語句都會使用一個不一樣的快照。 下面這個例子展現了一致性讀的工做狀況 首先打開客戶端鏈接,建表,開始一致性讀事物隨後插入數據: 而後,像以前那樣打開另外一個mysql客戶端鏈接。自動提交。而後插入一行並確認插入成功。 select 語句顯示的只有一行記錄。第一個事物插入的記錄目前是看不到的。 如今返回第一個mysql客戶端中,作提交操做,並檢查是否可見 如此一來,提交後,第一個鏈接插入的記錄在第二個鏈接中就能夠看到了,不信經過select看一下: 由於第一個鏈接提交後,其對錶作的全部變動對其餘鏈接都是可見的。 以前的例子中,咱們能夠隨時經過indormation_schema庫來查看鎖相關的信息。可是一致性讀不會產生任何鎖,所以下面的例子只是個空行 一致性讀原理對delete和update一樣適用 對前面的例子來講,若是咱們執行語句的時候加上 with consistent snapshot子句。那麼第二個鏈接插入的每一行都會當即被第一個鏈接看到。 Locking reads(讀鎖?鎖讀?) 鎖讀是另外一種保證數據一致性的方法。這種方式比一致性讀更強硬。由於它會鎖住相關數據,其餘鏈接根本不能訪問(那些數據)或者只能讀,除非當前事物結束。 鎖讀經過select中的兩個子句發起:LOCK IN SHARE MODE 和 FOR UPDATE。鎖的類型取決於使用了哪一個子句。 LOCK IN SHARE MODE 會阻止其餘鏈接修改經過SELECT語句返回的行。可是讀操做沒問題。 對於FOR UPDATE,SELECT語句的行爲和UPDATE很像。返回的行被鎖定而且不能被其餘鏈接修改和讀取,除非使用 READ UNCOMMITTED隔離級別。即便在這種狀況下,那些鏈接將仍舊沒法在共享模式下鎖定行。 若是當前事物的隔離級別是 SERIALIZABLE而且自動提交關閉,那麼LOCK IN SHARE MODE 子句老是加載了select後面,除非使用了 LOCK IN SHARE MODE模式。(the LOCK IN SHARE MODE clause is always added to SELECT statements, unless they use LOCK IN SHARE MODE 大家能翻譯嗎?) 下面的例子展現了LOCK IN SHARE MODE 如何工做 首先,打開一個mysql鏈接,建表建索引,索引很是重要,由於innodb的鎖就是基於索引來的。而後開始事物並在 SHARE MODE下檢索數據 而後打開另外一個mysql客戶端,嘗試查詢全部記錄而後修改其中兩行。其中一行是上面select返回的 a=1的行 如代碼展現,select沒問題,update a=3 也沒問題,可是 update a=1 的時候,因爲a=1被第一個鏈接鎖住了,則不得不等待。在本例中,咱們保持第一個鏈接不提交,最後因爲超時返回錯誤。一般,提交或者回滾操做以後,加在行上的鎖就會被釋放。 死鎖 有種組合鎖會搞出這麼一種狀況:事物之間互相阻塞。即持有鎖的事物還在等待別的事物釋放鎖。這種狀況叫作死鎖。innodb(或者像其餘須要處理這種狀況的引擎)有一種內部機制來處理死鎖。即中斷最晚進行插入,刪除,更新動做的那個事物。被中斷的事物就是犧牲者。 有時候,存儲引擎還可能在表級鎖上產生死鎖。若是是innodb表,能夠設置 innodb_table_locks=ON來讓innodb檢測表級死鎖。 併發環境下的死鎖是很常見的。當出現死鎖的時候,一個或者更多的事物會被中斷並拋出1213錯誤。這不叫事,應用程序捕獲了這個錯誤之後會從新開始事物。固然,也不是說很指望發生死鎖。若是常常有這種狀況,及時找出問題的根源解決爲妙。有幾種解決方式: 1小的事物不多會致使死鎖。若是容許,儘可能把事物寫小。語句中使用索引對於減小鎖的數量是頗有幫助的,以前的部分就說明了這點。不一樣的事物訪問同相同的表,表的訪問順序儘可能保持不一樣,好比若是一個事物訪問表的順序是 A B C,那麼另外一個事物應該避免使用這種順序,換一種,好比 C B A會更好。 2 一般和隔離級別無關,可是使用 read committed 或者 read uncommitted 隔離級別能夠較少產生由於讀鎖致使的死鎖。 可以使用 show engine innodb status 命令來診斷最近的死鎖。像下面的例子同樣。也能夠設置 innodb_print_all_deadlocks=ON,會把innodb的死鎖信息寫入error log中。 如今舉個死鎖的例子,搞一個死鎖很簡單。建立兩張表 t1 ,t2。包含一行記錄和惟一索引。外加兩個不一樣的mysql客戶端。第一個客戶端,使用select ... for update 在t1表上得到一個排他行鎖。第二個鏈接,在t2表上搞個一樣的鎖。而後,使用第一個鏈接去訪問第二個鏈接鎖住的行。第二個鏈接去訪問第一個鏈接鎖住的行。這樣,第一個鏈接會等待第二個鏈接釋放鎖,可是鎖確定不會被釋放,由於第二個鏈接還在等待第一個鏈接釋放它須要的鎖。這種循環的鎖就構成了死鎖。例子以下: 沒有任何輸出,鏈接1如今被掛起了,由於t2上的b=1正被鎖定着。 innodb檢測到了錯誤,而後鏈接2被中斷了。此時鏈接1會收到查詢結果。 咱們固然知道發生了什麼,可是假如咱們想看看死鎖的診斷信息。此時就能夠使用 show engine innodb語句了。執行它,而後找到 LATESE DETECTED DEADLOCK 部分 】 咱們須要的內容至關清晰明瞭。包括事物的鎖類型,對於每一個事物,還說明了致使死鎖的語句以及哪一個事物在等待哪一個鎖(((2) WAITING FOR THIS LOCK TO BE GRANTED))。最後一行給咱們提供了爲處理死鎖而幹掉的那個鏈接的信息。 事物 用戶能夠把一句或者多句sql封裝成一個事物。這些語句容許咱們明確的發起開始,提交以及回滾事物,通常這些都是隱含操做的(好比自動提交,以及有些隱式提交)。咱們還能設置具體的隔離級別。明確哪些事物是隻讀的;這些特性能夠幫助innodb作一些內部優化。 事物的生命週期 一般mariadb事物是以 START TRANSACTION 語句開始,以 COMMIT 或者ROLLBACK結束。BEGIN WORK和START TRANSACTION意思同樣,可是不能用在存儲過程當中,由於BEGIN 和END在存儲過程當中是做爲包圍代碼的關鍵字出現的。通常開始事物的語法以下: START TRANSACTION AND CHAIN 命令表明在上一個事物的commit或者rollback以後當即開始新事物,即後面不用再輸入 START TRANSACTION語句。 有些語句是非事物的,而且對當前事物會有一個隱含的提交操做。這樣的語句很是多,而且不一樣的服務器版本,具體的語句也可能不一樣。按照通常規則,全部的DML或者DCL和管理命令同樣,都是非事物的,DML也僅僅會在須要的時候涉及到臨時表。 默認autocommit參數爲 ON。能夠在全局或會話級修改。若是爲ON,那麼每條語句都會被認爲是一個事物,除非明確使用了 start transaction 語句. 若是關閉自動提交,那麼事物就由 start transaction 開始,其實若是你不寫這個命令也不要緊,由於它是隱含在第一個語句以前和每個commit或者rollback語句以後。 事物的隔離級別 mariadb 支持4種隔離級別: READ UNCOMMITTED,READ COMMITTED,REPEATABLE READ以及SERIALIZABLE。默認是REPEATABLE READ.能夠經過 transaction_isolation變量或者 --transaction-isolation啓動參數修改。固然也能夠在會話級使用 SET TRANSACTION 命令修改,好比這樣 固然,在事物開始之後再更改隔離級別確定是不行的。 隔離級別決定數據如何被與當前事物隔離的其餘事物訪問。也就是說,決定了其餘事物如何訪問被鎖住的行以及是否會生成快照。強的隔離級別會在一段時間內阻塞其餘鏈接,所以除非必須不然儘可能不使用。例如,若是能夠容許一些小錯誤,那麼強的隔離級別儘可能就不要用在須要訪問大量數據和統計計算的事物中。 read uncommitted 隔離級別 此隔離級別中,當前事物執行的讀取操做都會建立一個獨立的快照。讀操做讀取這些快照。這些快照頗有可能由一些當前還沒提交的事物中的臨時狀態組成,也就是說,讀到的數據有可能歷來就沒存在過表中。 read committed隔離級別 和read uncommitted 相同,read committed也會對每一個讀操做建立一個快照,但不一樣的是,它毫不會用沒提交的數據來建立快照,update和delete操做使用讀鎖,從不使用間隙鎖,也就意味着有可能出現插入幻行(不明因此)The UPDATE and DELETE statements, as well as locking reads, never use gap locks. This means that the insertion of phantom rows is always possible. repeatable read 隔離級別 此隔離級別中,一個事物中的全部讀操做只使用一個快照。這比read committed提供了更好的數據一致性保護。在update和delete操做數據時,記錄鎖會在惟一索引上生效,而且其餘索引的間隙鎖或者 next-key 鎖會阻止往掃描過的行中插入數據。 serializable 隔離級別 學習serializable能夠參照repeatable read。全部的非鎖類型的select操做都會自動轉換成 lock in share mode.若是咱們使用鎖類型的 select操做(for update),那麼serializable和repeatable read 沒什麼區別。當使用自動提交時,這兩種隔離級別都是同樣的。這就是爲何若是當前事物以當前查詢結束(就是查完這個事物就完了)則再也不須要鎖。 實際狀況中,serializable能夠用在一個事務中的全部查詢必須得到至少一個讀鎖時的狀況,好比下面這個例子: 其做用和影響和下面的例子是相同的,只是不用寫lock in share mode; 事物訪問模式 mariadb 10.0引入了事物訪問模式。有兩種:READ WRITE 能夠修改存在的數據。READ ONLY只能讀取數據。例外就是READ ONLY能夠修改臨時表中的數據,若是嘗試訪問其餘數據則會報錯。訪問方法能夠經過 SET TRANSACTION 命令修改。能夠在指定隔離級別的同時指定訪問方法,好比: 若是使用了自動提交,mariadb總能知道準確的事物訪問方式,若是關閉,或者事物經過start transaction語句開始,那麼 read write就是默認的訪問模式。 若是存儲引擎獲悉當前訪問模式是read only,那麼就能夠作出一些優化以提高併發操做性能。 元數據鎖 元數據鎖是從mariadb5.5中提出的一種特殊類型的鎖。當事物第一次訪問視圖或者表時就會得到元數據鎖。非事物表,好比aria 表也不例外,元數據鎖阻止事務刪除鎖定的對象或修改其結構。這是很是重要的,你必定不想在訪問表的時候,中途發現表沒了或者某個字段消失了。 若是一個鏈接嘗試執行ddl(好比alter table)來修改一個已經持有元數據鎖的表,那麼這個鏈接就會掛起直到元數據鎖被釋放。元數據鎖也有超時時間,經過lock_wait_timeout來定義,單位爲秒。默認值是 3153600,即一年。若是掛起超時了,那麼鏈接會收到1205錯誤。 如以前所說,元數據鎖在非事物表和視圖上一樣適用,這使得能夠使用事務訪問任何類型的實體。若是應用程序使用ddl來操做表和視圖,那麼 lock_wait_timeout應該被配置的稍微小一些,這樣應用程序就會及時收到1205錯誤。 mariadb 10.0中引入了一個叫作metadata_lock_info的插件。它能夠用來查看當前存在的元數據鎖。此插件跟隨mariadb發佈,但默認並未安裝。安裝以後會在information_schema數據庫中建立一個 metadata_lock_info 表,其包含如下幾列: thread_id: 持有元數據鎖的線程id lock_mode: 元數據鎖有幾種方式,具體取決於被鎖住的操做。 lock_duration:這指示元數據鎖在事務或語句的持續時間是否有效 lock_type:表明哪一種類型的鎖(好比表元數據鎖仍是存儲函數元數據鎖) table_schmea:鎖住對象的模式是誰 table_name:鎖住的表名 在show processlist輸出中,處於等待元數據鎖釋放的鏈接會在extra列中含有「 waiting for table metadata lock」字樣 讓咱們看一個死鎖的例子。使用兩個mysql客戶端實例。第一個建立一張表,開始一個事物,插入一行。這樣就會得到一個元數據鎖。咱們使用aria表來舉例證實元數據鎖在非事物表上一樣會起做用。隨後,第二個鏈接實例發起 rename table 命令,可是它不得不等待,接着,第一個鏈接中提交事物,而後第二個鏈接中的rename纔會被執行 第一個鏈接代碼以下: 第二個鏈接代碼以下: 不會有任何輸出,此鏈接正在等待元數據鎖釋放。 如今咱們來查看一下元數據鎖信息,方便起見,咱們使用第三個客戶端實例: 咱們能夠看到三個鎖,第一個鏈接的ID是4,它對 test.t表持有了一個共享寫元數據鎖,其經過修改表來呈現其餘鏈接。(???which presents other connections by modifying the table.)。第二個鏈接的ID是5,它持有了兩個意向排他鎖,即它在等待獲取元數據的排它鎖。 如今第一個鏈接提交事物,在提交先後咱們分別對這張表作一個查詢: 第一個查詢有效,是由於rename table還處在等待狀態,可是提交以後,一樣的查詢失敗了,由於表的名字已經被更改了。 須要記住的是,當元數據鎖被釋放之後,DDl語句會根據隊列順序執行。即使是當前持有元數據鎖的事物發起相似alter table這樣的命令,由於與它類似的命令已經被隊列進去而且須要優先執行。下面的例子展現了這種情景。第二個鏈接隊列了alter table,所以第一個鏈接執行alter table 就會失敗。若是應用程序使用ddl,那麼這種情景會致使不少問題而且難以處理。 鏈接 1 鏈接 2 客戶端展現了aria表上alter table的操做狀況,整個過程在第二階段中止,由於當前鏈接正在等待元數據鎖釋放。 鏈接 1: 不須要複製表的操做有如下幾種 1 重命名錶 2 更改表註釋 3 重命名列 4 更改顯示的數據類型大小 好比 int(3) 到 int(4) 5 對於 ENUM列,在ENUM列表的最後添加條目,好比ENUM('a','b') 新加一個‘C’變成 ENUM('a','b','c') 自mariadb 5.5以來,在innodb表上添加刪除索引已經不在須要複製整張表了。 mariadb 10.0中,一些額外的子句會添加到alter table後面,其中就有 ALGORITHM。能夠用來強制複製表來進行alter table操做(若是受到alter table bug的影響,則可能頗有用)或者須要使用一個內置的算法(複製表算一種算法,另外一種就是INPLACE內置算法)。這種情景下,若是內置算法不能使用,那麼就會生成錯誤。對於 ALGORITHM可選的值有 COPY,INPLACE或者DEFAULT(使用最佳算法) ONLINE選項和ALGORITHM=INPLACE等效 能夠使用LOCK子句,以便不使用鎖,或者只使用共享讀鎖或排他寫鎖。若是有更好的鎖策略可用,那麼LOCK子句不起做用(頗有用,若是咱們受併發環境下alter table 的bug的影響)。若是要求的鎖策略不可用,那麼就會報告一個錯誤。LOCK子句能夠使用的值有 NONE,SHARED,EXCLUSIVE和DEFAULT(使用較少限制的可用策略)(這段話我實在翻譯不通了。第一句的「以便不使用鎖是否是指的下面的 LOCK=NONE??」附上原文: The LOCK clause can be used so that no locks are used, or only shared (read) locks or exclusive (write) locks are used. If a better locks strategy is available, it will not be used (probably useful if we are affected by some concurrency-related bug in ALTER TABLE). If the requested lock strategy cannot be used, an error will be issued. The allowed values for LOCK are NONE, SHARED, EXCLUSIVE, and DEFAULT (which uses the less restrictive available strategy).) 看下面的例子: 對於innodb表,information_schema中的 innodb_metrics會有詳細的關於當前執行alter table的狀態信息。對於aria表,能夠使用mysql 命令行客戶端來查看alter table的執行過程。 //* percona 有一個有用的工具:pt-schema-change,包含在percona toolkit中。它建立一張如出一轍的空表,在這張表上修改其結構,而後複製數據到這個新表中。最後用新表來替換老的。這個過程比常規的alter table要花費更多的時間,可是其表上不會有鎖。mariadb 10.0中,不少狀況下這個工具已經不須要再使用了。可是這個工具對於那些修改表結構須要長時間持有鎖的老版本的mariadb仍然很是有用,在使用這個工具以前,必定要當心認真讀percona的文檔。*// 總結: 本章咱們學習了併發環境下innodb存儲引擎如何保證數據一致性。首先介紹了鎖和快照如何工做。從底層學習innodb工做機制以理解innodb事物工做原理是很是重要的。咱們還討論了隔離級別以及每一種隔離級別如何使用鎖和快照對數據進行保護。還介紹了在負載繁重的數據庫中處理死鎖的通常方法,可是身爲一名dba應該儘可能避免這種問題的產生。咱們還討論了元數據鎖,用來保護當前事物操做表或者視圖時不會被中途修改結構。 在本章的最後,咱們討論瞭如何避免alter table產生的會長時間持有的鎖。 下一章咱們將會學習管理用戶和鏈接,以及如何限制它們的資源和處理一些安全問題 第五章 用戶和鏈接 本章將會介紹mariadb提供的關於安全特性的工具。讀者必須有一點用戶帳戶和權限管理的基礎知識才行,好比像grant,revoke這種語法,以及權限如何應用到數據庫,表和列。 本章主要內容有: 用戶帳戶 角色 SSL鏈接 認證插件 用戶資源管理 線程池 監控鏈接狀態。 用戶帳戶 mariadb的訪問控制基於帳戶。所謂帳戶,就是鏈接到服務器的由用戶名和主機名拼成的一個字符串(不曉得這麼理解對不對,帳戶這個概念並不等同於用戶,而是用戶+主機名構成的字符串才叫作帳戶,可是也不必去咬文嚼字)。帳戶的語法定義通常是這樣的(單引號可選,若是沒有特殊字符的話能夠省略): 'username'@'hostname' 建議建立用戶的時候使用 create user命令,而後使用grant給其授予相應權限。默認狀況下,mariadb容許給一個不存在的帳戶受權,若是進行這種操做,那麼相應的用戶就會被自動建立出來。若是說某一天你受權時把用戶名輸錯了,結果系統就給你建立出一個新用戶,這樣感受很不爽,因此能夠經過 SQL_MODE的NO_AUTO_CREATE_USRE變量來關閉這種機制: 在一個帳戶中(注意這裏是帳戶,老外把account和user分的挺細),你也能夠使用通配符,好比 'user_'@'%' 匹配了全部以user用戶名開頭的,來自全部主機的鏈接。當一個帳戶嘗試鏈接進來的時候,mariadb會在 mysql.user表中查找對應的用戶名和主機名(或者ip地址)的匹配項。若是匹配成功,mariadb接着校驗密碼。密碼被加密在system表中,而且客戶端在發送密碼以前也要對密碼作加密處理。若是密碼不匹配,或者沒有找到匹配的帳戶條目,則鏈接會被拒絕 若是密碼錯誤,則能收到這樣的反饋信息: 此反饋已經提供了足夠咱們診斷問題所在的信息,好比像用戶不存在或用戶不能從某主機訪問或密碼不正確,均可以。若是括號中顯示的password:no,則表明你忘了輸入密碼。 //* 帳戶認證加密算法使用的是hash算法,和PASSWORD()函數同樣。其派生自SHA算法。許多應用程序都會使用PASSWORD()函數,但僅僅是在內部使用,強烈推薦不要在SQl查詢中調用這個函數 *// 有時,多個帳戶名能夠匹配到一個用戶名和主機。這種狀況下,mariadb就會使用最小匹配原則,好比。'user01'@'mandarino'比'user_'@'%' 匹配程度更精確,也更有選擇性,若是有這樣的帳戶鏈接進來,當其發起命令的時候,mariadb就會按照最小匹配的那個帳戶所擁有的權限去校驗,關聯到其餘帳戶的權限都會被忽略。 經過角色受權 直接管理mariadb服務器中多個帳戶的權限是件很痛苦的事情。假如咱們有20個用戶須要授予相同的權限,並且未來某個時候還須要更改數據庫結構,相應的20個用戶的權限也要作相應的調整,最少狀況下是20個grant語句。這項工做會極其麻煩並且還容易出錯。 正因如此,mariadb10.0引入了遵循 SQL:2003標準的 角色功能。這樣,咱們能夠把一個或一組權限授予一個角色,而不是單個帳戶,而後能夠把這個角色授予某一個或多個帳戶。這樣多個帳戶就都有了相同的角色。這樣,當用戶對數據庫作出請求時,mariadb會根據其具備的角色來對用戶的請求作出反饋。若是數據庫方面須要作什麼改動,調整權限只須要修改角色的權限便可。 角色能夠經過 create role 和drop role 來建立和刪除。當建立一個角色的時候,也能夠選擇這個角色的管理員。參考以下代碼: 若是沒有使用 with admin ,那麼角色的管理者就是當前鏈接的用戶。管理員能夠使用grant 和revoke語句來把角色關聯到帳戶上,或者刪除這種關聯關係。須要注意的是,角色能夠關聯到另外一個角色(能夠給角色授予角色)。若是咱們有不少角色,這就頗有用。好比能夠把一些角色須要的公有(也就是說N多帳戶可能都應該至少擁有的一些權限)的權限都歸到一個角色中,而不是給每一個角色都去單獨地分配權限,另一些權限能夠分給其餘的角色。下面這個例子展現了grant,revoke的用法 grant 一樣能夠用來給角色受權。授予角色權限,再把角色授予用戶,則用戶就有了其相應的權限。爲了撤回授予的權限,能夠使用revoke命令。不管如何,語法都是相同的,和給帳戶受權撤銷權限同樣。好比這樣: 注意,當用戶被授予某種角色,即使他們鏈接到服務器,也不會自動使用該角色。相反,客戶端還須要明確使用set role語句來聲名角色,而且一次只能具備一種角色身份(若是是角色授予角色,角色又關聯到用戶的那種,權限自己不會受到影響)。current_role()函數返回了當前活動狀態的角色,好比這樣: 須要注意的是information_schema數據庫中有兩張表存儲了角色相關的信息。 APPLICABLE_ROLE 包含了當前用戶能夠使用SET ROLE 設置成哪些角色的信息。例如向誰授予這些角色以及誰能夠授予這些角色。 ENABLED_ROLES 表包含了開啓的角色名稱和授予給其餘角色的角色名。 若是一個或多個角色分配給用戶已明確選擇的角色(經過 SET ROLE明確選擇,十分拗口),那麼這些角色也會被展現出來,好比: 如上,當前鏈接用戶是josh,咱們把writer角色授予josh。這樣已經授予給writer角色的reviewer角色會自動的關聯到授予了writer角色的用戶上。故在enabled_roles表中能夠看到兩條角色。 經過SSL鏈接到mariadb mariadb 支持安全套接字層(SSL)鏈接。若是想使用SSL,mariadb必須經過編譯安裝yaSSL或者OpenSSL。二進制安裝包已經內置了yaSSL,能夠查看have_ssl服務器變量來檢查咱們的服務器是否支持SSL。若是爲YES,則支持,而且已經配置了。若是是DISABLED,則SSL是支持可是尚未配置。若是是NO,則不支持SSL。例如: 爲配置SSL,首先須要建立一個證書(由CA發佈),爲須要使用SSL的服務器和客戶端頒發公鑰和私鑰,證書和KEY能夠經過openssl程序來生成(免費軟件)。一般UNIX類系統都有安裝,windows的話能夠另行下載。 //* 本小節內容假定讀者對SSL和建立證書過程都有個大體瞭解 *// 建議密鑰串長度使用4096,比2048或者更短的要安全。固然,更長的密鑰串表明了網絡間會話更高的負載需求。可是測試代表,4096和1024兩種長度的密鑰串在鏈接時差距比較大,當進入正常使用時看不出什麼區別。不一樣之處是若是有不少短鏈接的話,性能負載比較嚴重。請記住,SSL自己引發的開銷一般會佔據總查詢執行時間的一半或更多。 驗證證書和密鑰是否到位而且有效的例子以下: 如今咱們須要讓mariadb知道證書和密鑰的位置。讓咱們把相關信息添加到mysql的[mysqld]一欄中。 固然也能夠使用啓動選項: 在[client]處須要添加相同的內容: 這樣就能夠使用SSL來鏈接到服務器了。 //*最好仍是寫到配置文件中,免得下次忘了*// 還須要一個使用SSL的帳戶。若是該帳戶嘗試經過非加密方式鏈接,則鏈接會被拒絕,無論帳號密碼是否正確。使用grant命令便可。 這個例子中,咱們會強制u1用戶使用SSL加密方式鏈接到服務器。若是想要對用戶的安全性要求更高,還能夠在REQUIRE以後跟一些選項,經過AND添加多個。選項以下: NONE:能夠使用SSL,但不是必須 SSL: 此選項說明須要SSL加密,而不對其特性有任何要求 X509:經過x509認證 ISSUER 'str': 此選項說明須要由指定的受權機構發佈的有效X509證書 SUBJECT 'str': x509認證須要特定的subject(???我也不是很清楚) CIPHER 'str':須要使用x509認證,而且鏈接必須使用一種特定的加密方法 下面的例子展現了上述所說選項: 如上,u1用戶從本地鏈接不須要加密,可是若是從其餘地方鏈接,他必須以SSL方式,使用特定的證書機構(單引號內的一長串)頒發的證書,以及使用RSA-SHA加密算法進行鏈接。 認證插件 mariadb支持認證插件。這些插件能夠以不一樣的方式來完成登陸和退出操做。這用於防止用戶經過外部程序來通MariaDB服務器的驗證。有些插件須要與客戶端適當交互。客戶端插件會自動加載而且不須要安裝。 目前mariadb 10.0有4種認證插件: mysql_native_password: mariadb 默認認證插件 mysql_old_password: 老版本,低安全性,在mysql 4.0,甚至是mysql 3.23時使用的插件 unix_socket: 使用Unix用戶的證書 pam:使用UNIX類系統的PAM 最後兩種默認未安裝。能夠經過如下命令安裝 未來mariadb還會支持更多的插件。(中間省略客套話)。具體的插件支持列表能夠經過如下語句進行查詢 若是你想要某個帳戶鏈接到mariadb時使用特定的認證插件,那麼經過使用create user 和grant語句就能夠完成,語法以下: 上例中,明確聲明瞭 federico用戶使用默認的mariadb認證。隨後,咱們須要這個用戶經過unix_socket插件進行鏈接。例子以下: USAGE 是一個虛擬的權限,若是咱們不想授予任何真正的權限,就能夠添加這個關鍵字,由於不寫個權限又會報語法錯誤。以前例子中,咱們使用個USAGE來使 federico得到經過unix_socket來鏈接到服務器的功能。 爲了完成這個例子,讓咱們看看用戶如何鏈接到mariadb。 以federico用戶登陸系統shell,並進入mysql命令行客戶端: 成功進入!由於咱們使用的是federico系統帳戶,而對於mysql中的同名帳戶又開啓了unix_socket插件。 如今,咱們換成root試試: 如你所見,換成root就不行了,可是,你能夠使用 --user選項,以特定用戶方式鏈接到服務器: 即在客戶端做爲適當的用戶運行時,即可以鏈接。 //* 注意,像上面這種--user,只能是系統帳戶是root才能用,畢竟不能隨即是個誰都能以特定用戶身份登陸到mysql。 *// mariadb能夠經過 grant命令來限制帳戶的系統資源使用狀況。限制以下: • MAX_QUERIES_PER_HOUR:容許用戶每小時執行的查詢語句數量; • MAX_UPDATES_PER_HOUR:容許用戶每小時執行的更新語句數量; • MAX_CONNECTIONS_PER_HOUR:容許用戶每小時鏈接的次數; • MAX_USER_CONNECTIONS:容許用戶同時鏈接服務器的數量; 上面這些值默認爲0,表明不作限制。可是MAX_USER_CONNECTIONS是個例外,若是它爲0,那麼還有個全局服務器變量 max_user_connections,它默認也是0,表明不作限制。用戶能夠查詢此變量的會話值,以瞭解此賬戶能夠創建的最大併發鏈接數。 限制用戶資源的大體語法以下: grant命令有一些語法上的要求,好比說它必須得有一個權限,因此這裏使用虛擬的 USAGE權限。隨後跟着 WITH關鍵子,後跟具體的資源限制參數。 下例中展現瞭如何查看當前帳戶容許的最大同時鏈接數,注意,0表明不限制。 //* 若是某個帳戶達到了它的限制,咱們又想臨時放開以讓它完成工做,能夠從新配置帶有 HOUR這種這樣的參數。可是這種方式不適用於MAX_USER_CONNECTIONS,它不是以每小時爲單位的限制量。 值得注意的是,沒有辦法爲單獨用戶(注意用戶和帳戶的區別)從新配置這些限制。在從新配置完畢以後,須要使用 FLUSH USER_RESOURCES命令刷新資源限制信息,使用FLUSH PRIVILEGES 或者 mysqladmin reload 也能夠完成,由於他們都會從新加載整個權限表 *// 通常來講,mariadb和mysql都會在客戶端每次鏈接到服務器的時建立一個線程。這種機制叫作「one thread per connection」,這也是大多數操做系統的默認機制,惟一例外的是windows(從vista開始) 大多數狀況下,mariadb都會用來承擔OLTP類型的工做。其會常常性地修改數據,好比絕大多數網站和桌面應用。這種工做負載狀況一般是一個session鏈接進來,而後執行了一個短而快的事物,隨即關閉鏈接。若是有許多用戶,則意味着在短期內會有許多session鏈接到服務器。那麼此時「one thread per connection」這種機制就會暴露出劣勢,由於建立和銷燬線程須要耗費必定的cpu和內存資源,針對這種小而快的鏈接不停作的建立銷燬線程這種動做實在是有點浪費資源。 mariadb5.1中,提出了一個新的線程管理方法——線程池。這種概念的實現是每一個線程能夠管理多個鏈接,每一個線程都是組中的一部分。mariadb 5.1中,線程數量是固定的。但在mariadb5.5中,對線程池作了重構。此時實現方法是若是當前的線程數量不足以知足新鏈接要求,則會爲新鏈接建立新的線程,而且當鏈接再也不活躍時銷燬線程。可是總會保持一個固定的線程數量。這個數量若是過低,那麼併發鏈接就不會從這種機制中獲益,若是這個數量過高,又會白白地浪費資源。 須要說明的是線程池管理方法經過在一組中隊列多個線程以免線程建立和銷燬的開銷,能夠提高OLTP的全局性能,可是對於每一個獨立的語句和事物可能會慢一些。例如,以前若是執行一個 select version(),那麼就會當即返回結果,可是若是使用了線程池,那麼服務器還須要作一些更復雜的操做才能進行真正執行這個語句。 線程池方法在windows上稍有不一樣,畢竟它依賴於本地的線程池管理方法。至於其餘操做系統,mariadb都有其本身的線程池管理方式。從用戶角度看,windows上的能夠使用的配置變量和其餘系統有些不一樣。在windows早先版本中,好比vista以前的版本,並不支持線程池,只能使用原來那種「one thread per connection」的方式。 激活線程池 開啓線程池須要在配置文件加入以下內容: thread_handling=pool-of-threads 對於windows,比vista還老的版本,這個選項會被忽略掉,比vista新的版本,線程池功能又是默認開啓的(和別的系統真的很不同) 若是這行是寫在全局配置文件中,而且你不想使用線程池,則能夠經過將下面這行添加到本身的配置文件來覆蓋上面的參數: thread_handling=one-thread-per-connection 線程池監控 能夠經過thread_handling變量查看是否使用了線程池機制 有兩個變量能夠用來監控線程的活動狀態: threadpool_threads: 此變量用來查看線程池中的線程的總數 threadpool_idle_threads:此變量表明線程池中空閒的線程的數量———由於線程處於空閒或者正在等待鎖釋放。這個值在windows中不會被監控 若是使用了「one thread per connection」的方式,則以上兩個變量都是0,好比: 配置線程池方法 (說了一大堆就是說注意windows和unix類上面的區別) 線程池的配置變量信息能夠經過如下命令查詢 相似這樣: UNIX系統中配置線程池 如下線程池變量能夠配置在UNIX系統中 thread_pool_size: threadpool中group數量,默認爲cpu核心數,server啓動時自動計算.如下內容摘抄自百度: thread_pool_size是一個很是重要的參數,控制thread pool的性能,具體表現爲thread group的數量。只能在server啓動以前設置,咱們測試thread pool的結果以下: • 若是主存儲引擎是innodb,thread_pool_size設置在16至36之間,大多數狀況設置在24到36,咱們尚未發現什麼狀況須要設置超過36,也只有一些特殊的環境須要設置小於16. • 使用DBT2或者sysbench作測試的時候,innodb引擎下一般設置爲36個,若是在一些寫入特別多的環境,這個值能夠設置的更小一些。 • 若是主存儲引擎是myisam,thread_pool_size須要設置的更低,咱們推薦的值是4到8,更高的值可能會對性能有負面影響 原文最後舉例,好比若是咱們有一臺服務器有4cpu,跑着mariadb和web服務,能夠只讓mariadb使用其中3顆cpu,則設置這個參數爲3 thread_pool_stall_limit:timer線程檢測間隔,單位爲毫秒,默認500, 這個參數對於處理阻塞和長時間執行的語句很重要。這個時間是從一個statement開始執行到執行完成總花費的時間,若是超過設置值就被認定爲stalled,此時線程池也開始容許執行另一個statement。 通常這個值設置爲你99%的statement能夠執行完的時間。好比我慢查詢設置的是0.1,那麼這裏就設置爲10。另外能夠經過SELECT SUM(STALLED_QUERIES_EXECUTED) / SUM(QUERIES_EXECUTED) FROM information_schema.TP_THREAD_GROUP_STATS; 來獲取stalled的比例,這個值儘可能的小,爲了不stall,能夠調高thread_pool_stall_limit的值。原文:當出現線程停頓(stalled),而且超時,那麼線程池將會嘗試喚醒線程或者建立一個新的線程。若是線程數量達到了 thread_pool_max_threads指定的值,則不會建立新的線程。 thread_pool_max_threads: threadpool中最大線程數目,全部group中worker線程總數超過該限制後不能繼續建立更多線程,默認500,該參數適用於全部操做系統 thread_pool_idle_timeout: 線程最大空閒時間,單位爲秒,超過限制後會退出,默認60 thread_pool_oversubscribe: 一個group中線程數過載限制,當一個group中線程數超過限制後,繼續建立worker線程會被延遲.原文:此變量爲服務器內部使用,用戶不該該去更改它,寫在這裏的緣由僅僅是由於會經過 show variables like 'thread_pool%' 顯示出來。 windows中配置線程池 注:如下兩個變量一樣適用於UNIX類系統。 thread_pool_min_threads:線程最少數,當不須要時,windows能夠關閉該線程,可是最終數量不得低於該限制。 thread_pool_max_threads:和上面說的同樣,不知道爲啥這裏又提一次。 配置變量調優 如今咱們列出使用線程池可能出現的問題以及如何調整這些參數以優化性能。 有時,一個線程爲了完成一些操做會鎖住幾張表。好比,若是發起了 flush tables ... with read lock 命令對非事物表進行物理備份(此內容會在第八章討論),這時全部的線程(或多個線程)都會被阻塞。一般這會致使線程池繼續建立新的線程(好比上面說的超時參數,在不達到最大線程數量的時候就可能經過建立新線程來解決問題),可是這不只解決不了問題,反而還會浪費資源。所以能夠把 thread_pool_max_threads 設置爲比較低的值以免建立相似這樣的線程。 有些負載分佈很不均勻,有時候會在一段時間暴漲,鏈接數猛增。可是以後又只剩下爲數很少的活動線程。若是說在低峯時段,服務器仍然須要爲爲數很少的新鏈接不停的建立線程,銷燬線程,顯然是很不划算的,所以咱們但願mariadb在線程池中儘量多保留一些線程以供偶爾來的新鏈接使用。在unix上,咱們建議調大 thread_pool_idle_timeout參數,最好能夠調整成比兩個負載波峯之間的時間段更大的超時時間。至於在windows上,很是簡單,經過 thread_pool_min_threads參數保留最少線程數便可。 對於數據倉庫,幾乎不會從線程池功能上得到什麼性能提高,畢竟和OLTP大不同。產生報表會須要訪問大量數據,這樣的訪問方式卻是不會產生鎖(看第4章),可是會長時間阻塞隊列中的語句。爲避免這種問題,能夠把 thread_pool_stall_limit設置的低一些。 搞定阻塞的線程 若是使用了線程池,當一個客戶端在全部的表上都得到了鎖,並持有很長時間會發生什麼?事實上其餘線程會被阻塞。爲解決此問題。mariadb將會建立更多的線程。可是沒用,由於每一個新建立的線程依然會等待鎖釋放。直至達到 thread_pool_max_threads的限制(達到限制也解決不了阻塞狀態,只是不會建立新線程了)。此時,服務器將會拒絕全部鏈接,而且DBA也不能鏈接到服務器查看到底發生了什麼。爲了不這種狀況。增大線程池限制也算個辦法,可是這會致使線程數量一直都保持很高,其中又有不少是無用的。(我以爲這種弊端做者解釋的並不對,增大最大限制不會在全部狀況下致使總體變大,這是增大 thread_pool_mix_threads纔有的狀況,對於unix,除非最小線程數量是經過 thread_pool_max_threads和公式計算得來。問題的關鍵是若是一直阻塞,最終結果依然是達到最大限制。) 解決辦法就是配置一個專有的extra端口,這樣的鏈接會使用「one thread per connection」的方式。這樣的鏈接數量有限制,一般容許1個就足夠了。具體變量以下: extra_port:指定額外鏈接的端口號 extra_max_connections:容許使用額外端口號進行鏈接的併發鏈接數。 //* 這項技術也能容許鏈接進入以完成工做,不過是以「one thread per connection」的方式。可是 extra_max_connections得足夠大才行 *// 監控鏈接 show processlist命令能夠返回當前的活動鏈接。其中 information_schema數據庫中的 processlist表還包含一些額外信息。咱們很快討論它。一樣,在 performance_schema數據庫的 threads表中也包含了 show processlist命令返回的信息,以及其餘列。一般 show processlist會返回簡明扼要的信息。processlist表更高級一些,它能夠用在存儲程序中。 下面的例子展現了 processlist表和 show processlist命令的輸出結果: 下面這張列表展現了 processlist表和 show processlist命令輸出列的含義與不一樣之處(我就不翻譯了,幾乎都是見名知意的字段。) 查詢threads表不會產生鎖,可是訪問performance_schema數據庫會致使性能問題,會影響不少服務的正常運行。這就是爲何mariadb10.0中默認是關閉performance_schema數據庫的。它不只存儲了客戶端的鏈接信息,還包含了全部線程甚至內部線程信息。threads表包含了show processlist命令返回的全部內容,皆是以大寫的 PROCESSLIST_前綴展現的。還包含其餘幾列: thread_id:線程id,和processlist_id不同。 name:線程的類型,好比與客戶端相關的鏈接,該值多是 thread/sql/one_connection. type:若是是 BACKGROUND,則爲mariadb內部線程;FOREGROUND則是能夠經過 show processlist展現出來。 PARENT_THREAD_ID:父線程ID ROLE:總爲NULL,目前沒什麼意義,能夠忽略 INSTRUMENTED: 是否在performance_schema數據庫中跟蹤線程活動狀態.(PO個例子) THREAD_ID 列能夠與performance_schema數據庫中的其餘表關聯查詢,好比這樣: 下面這張表展現了 COMMAND列的含義。(與processlist表和show processlists相同,此處不作翻譯,見名知意) PROCESS 的STATE列 STATE列包含線程當前正在作什麼,有不少值,可是此處只列出主要的一些(一樣不作翻譯) 中斷鏈接 當查看process列表的時候,你可能會注意到其中一些進程很慢,或者阻塞了其餘進程。也可能你發現它們一直處於沉睡狀態。你想中止它們。此時能夠使用KILL命令。mariadb對此命令有不少可選參數,對比mysql中的語法,大體以下: 默認KILL會終結一個鏈接。 CONNECTION關鍵字只是讀起來順嘴,與不含connection的KILL同樣:它會終止給定thread_id有關的鏈接。若是使用了 QUERY關鍵字,那麼只有鏈接執行的語句會被殺死,但鏈接自己還會保持。 鏈接的ID或者語句的ID必須顯式指定。即使是對於QUERY關鍵字。 僅當指定了ID關鍵字時,MariaDB纔會去查詢ID。 另外一種作法是能夠加USER關鍵字,後接具體的帳戶名稱或者用戶名,這樣其用戶相關的全部鏈接或查詢都會被殺死。若是是想殺死屬於咱們本身的鏈接,也能夠使用current_user()函數。 殺死一個查詢或者鏈接,使用SOFT選項雖然慢,可是更安全,這也是默認選項。使用HARD選項速度很快,可是方式很野蠻,可是若是使用SOFT太慢的話,用一次HARD 也無妨,可是在HARD 操做以後,數據有可能損壞,此處展現一下該命令如何工做 1 KILL命令給目標鏈接打個標記,若是該鏈接被KILL標記了,則在 show processlist中的INFO列會顯示爲 'Killed' 2 若是是安全地進行中斷當前操做,目標端會校驗標記是否已設置,若是是,那麼鏈接或者語句就會被中斷。 3 若是是非安全的中斷,經過HARD KILL的鏈接會被當即中斷,可能會使表處於不一致的狀態。 若是鏈接涉及了aria或者myisam表,那麼一是數據有可能損壞,二是若是表上有索引,那麼索引須要重建。 下面展現了KILL的例子: 使用mysql 命令行客戶端,執行以下: 此命令無害,可是對於演示例子很是好,由於它只是讓當前線程暫停2000秒. 而後,開啓另外一個客戶端執行下面命令: 輸出內容不少,可是咱們只關心其中幾個,好比咱們知道了線程ID爲 9.而後執行下面的命令: 能夠經過 show processlist命令查看KILL的工做狀況。 若是是一個非活動狀態的鏈接,在其達到wait_timeout參數設置的超時時間後會被自動關閉。 總結: mariadb 支持經過SSL進行鏈接以保證更好的安全性。認證插件也能夠使用額外的認證源來替代mariadb本身的認證方式。咱們還嘗試使用unix_socket來演示瞭如何使用系統認證。PAM認證也是支持的。還有經過限制用戶每小時能夠執行的語句,以阻止其消耗太多資源。 有可能用戶會經過特定的主機和SSL或者認證插件來進行鏈接。徹底能夠實現,由於mariadb的權限驗證基於帳戶,帳戶是由用戶名和主機名組成。其帳戶還能夠使用LIKE 通配符。 mariadb支持兩種線程管理方法:「one thread per connection」 這種傳統方式,以及線程池這種新方法,線程池會把線程分紅組,以提高鏈接性能(針對OLTP).針對unix和windows,mariadb有兩套配置方案,實施的時候須要注意。 show processlist命令,information_schema.process表,performance_schema.threads表能夠幫助監控鏈接的活動狀態。若是有必要則能夠使用KILL命令殺死你想要終結的鏈接。 下一章咱們會討論mariadb中的cache和多種存儲引擎. 第六章 Cache (寫在本章開始:buffer,cache 都翻譯成緩存,或者緩衝,但咱們知道其實英文含義並不相同,因此,我儘可能) 表和索引一般會佔用大量存儲空間,好比像磁盤,SSD,或者閃存設備。訪問這些設備速度很慢。若是服務器不得不常常這麼作的話,那麼I/O就會成爲性能瓶頸。爲避免訪問磁盤設備,mariadb和存儲引擎提供了幾個DBA應該掌握的CACHE。本章將會涉及如下幾個主題(並不是不作翻譯,專業詞彙儘可能保持原樣,無法再翻譯了) innodb buffer pool 和 doublewrite buffer myisam key cache aria page cache query 和 subquery cache table open cache main per-session buffer //* 在討論具體的cache分配以前,有些注意點須要說明一下。許多權威性著做,好比《mariadb knowledege base》或者mysql 手冊都建議給innodb buffer pool設置比較大的內存,或者若是不少表都是非 innodb表,就把默認存儲引擎的main cache設置大一些。許多文章中都建議把buffer pool設置爲物理內存的70%到80%.對於myisam和aria來講,由於它們只有key須要被存儲引擎緩存,不須要很大的內存。至於緩存數據文件,mariadb則依賴於操做系統。除此以外,dba應該認真思考如何爲其餘cache分配內存。好比query cache,若是用,則確定小不了。若是有不少併發鏈接,則per-session cache也會佔用至關大一部份內存。並且,這些建議也僅僅是針對一臺服務器上只運行一個mariadb實例的狀況,其餘程序資源分配一樣須要考慮進去。 *// innodb cache innodb存儲引擎應用很是普遍,會配置它的參數很是重要。innodb buffer pool能夠加速讀寫操做。所以DBA須要掌握它的工做原理。 doublewrite buffer 是一種保證一行記錄寫入文件時毫不會處於半寫狀態的機制。對於寫負載很重的系統,能夠關閉這個特性以提升速度。 innodb pages 表,數據和索引組成了page(innodb最小的存儲單元)。其存在於cache和文件中。一個page由1或2行數據和一些空餘空間組成。已使用的空間和page總大小的比率叫作 fill factor(填充因子,就是頁佔用率) 若是改變了page的大小,則填充因子也會相應改變。innodb會保持填充所以處於15/16。若是page填充因子低於1/2,innodb會把該page和其餘page合併。若是行數據是順序寫入,填充因子會介於 1/2到15/16之間。填充因子太低,表空間浪費嚴重,若是填充因子太高,當由於update致使行長度增加時,那麼就會產生重組,這對性能會有消極影響(相似於oracle中的pct_free,行鏈表接,行遷移內容) 變長格式列(好比 TEXT,BLOB,VARCHAR 或者VARBIT)會存放在一種叫作overlow PAGE的數據結構中。這樣的列叫作off-page列。它們由DYNAMIC行格式管理,DYNAMIC行用在大多數表中,並提供向後兼容。行格式會在隨後講到 page毫不會改變它本身的大小,而且全部page大小都是相同的,可是頁大小能夠配置,好比 4KB,8KB,16KB.默認是16KB,這個大小是針對多種負載狀況選擇的最優大小,優化了全表掃描。然而,更小的size能夠提高OLTP的性能。由於插入頻繁,而每次申請的內存數量會更小。另外一個更改page size的因素就是它對innodb表壓縮有着很大的影響。(第七章會討論) 能夠經過配置文件中的innodb_page_size 變量更改page size,重啓生效。 innodb buffer pool 若是服務器主要使用innodb表(絕大多數都是這樣),那麼配置buffer pool就是一個很是重要的工做。理想狀態下,buffer pool應該能容納全部的innodb數據和索引,來讓mariadb無需訪問磁盤就能獲取數據。數據變動會在buffer pool中執行,隨後再寫入磁盤以減小I/O 操做。固然,若是buffer pool不足以容納全部的數據,那麼會把訪問頻率最高的數據放進去。 buffer pool 默認大小128MB,能夠更改,生產環境顯然過小,若是是開發環境,又用不了這麼大,此參數最小值爲5MB,給開發用妥妥沒問題。 Old 和 new page 咱們能夠把buffer pool想象成由data page組成的鏈表,其鏈表使用LRU算法。此鏈表分紅兩部分:new鏈表包含最近常用的頁,old鏈表包含最近不多使用的頁。 每一個子鏈表的第一個頁叫作 head (頭). old鏈表的頭又叫作midpoint(中點).當一個不存在於buffer pool中的頁被訪問的時候,它會被插入到midpoint中。old鏈表中的其餘頁逐一日後挪一步,最後一個頁被丟棄。 當old鏈表中的頁被訪問的時候,它就會移動到new鏈表的head(頭部). //* 原文這裏是算法介紹,提供了一個地址: http://cs.gmu.edu/cne/modules/vm/yellow/lru.html *// 當new鏈表中的一頁被訪問的時候,該頁會移動到new鏈表的頭部。如下幾個變量能夠影響上述算法。 innodb_old_blocks_pct: 此變量定義保留到old鏈表緩衝池的百分比。可選範圍爲5到95,默認是37(3/5)。 innodb_old_blocks_time:若是該值非0(以毫秒爲單位),則進入老鏈表的頁必須在達到這個參數設置的時間以後再被訪問纔會被提高到新鏈表的頭部,若是沒有達到該參數設置的時間限制,即使被訪問多少次,也不會提高到新鏈表頭部。若是爲0,則只要被訪問到,當即提高到新鏈表頭部。 innodb_max_dirty_pages_pct:定義了內存中能夠保留的最大髒頁的百分比。此機制會在本章後面講解。此參數並不是硬性限制,可是innodb會盡可能知足該限制。該參數許可範圍爲 0到100,默認爲75.增大該值能夠減小寫操做的頻率,可是若是意外宕機,則再次開機須要花費更長的時間(相似於oracle中的online log 大小,越大實例恢復速度越慢.) innodb_flush_neighbors:若是爲1 ,則當髒頁寫入磁盤時,臨近的頁也會被寫入。若是爲2,同一區塊中的髒頁會被一塊兒寫入。若是是0,則只有超過 innodb_max_dirty_pages_pct的部分或者當它們被buffer pool踢出時纔會刷寫到磁盤。默認值是1.這種將多個IO合併爲1個IO的操做僅對於傳統機械硬盤有性能提高。對於寫入量很大的負載可能須要更加積極的刷寫策略,可是若是頁面寫得太頻繁,則會下降性能。 buffer pool 實例 在mariadb5.5以前,innodb只有一個buffer pool實例。這樣併發線程會被互斥機制阻塞而成爲性能瓶頸。若是併發很是高,而且buffer pool很是大,這種阻塞現象會尤其明顯。所以把大的buffer pool切分紅多個實例能夠解決此問題。 多個實例僅在緩衝池大小至少爲2 GB時才展示出優點。每個實例都應該設置至少1GB。若是buffer pool的大小少於1GB,則mariadb會忽略該配置並只使用一個實例。此特性對於64位操做系統更有用. 如下兩個變量控制buffer pool的實例和大小 innodb_buffer_pool_size:此變量定義buffer pool的總大小(非單獨的實例). 注意,實際尺寸將比這個值大約多出10%,多出的10%專門用於change buffer (第七章表壓縮提到) innodb_buffer_pool_instances:定義buffer pool的實例數量。若是爲 -1,則innodb自動決定實例數。最大值爲64.UNIX上默認爲8,windows上要看具體的innodb_buffer_pool_size設置。 Dirty pages 髒頁 當一個用戶執行一條語句修改了buffer pool中的數據。innodb會先在內存中修改。僅在buffer pool中被修改過的頁叫作髒頁,未被修改過的頁或者已經被寫入磁盤的頁都叫作乾淨頁 clean page(翻譯成中文好彆扭) 注意!變動的數據記錄會寫入到redo log中。若是在髒頁寫入數據文件以前發生宕機,innodb一般能夠恢復這些數據,包括最新修改過的內容。經過讀取redo log和 doublewirte buffer便可完成。doublewirte buffer會在後面說起。 把髒頁刷寫到innodb數據文件的線程,在mariadb10.0中叫作 page cleaner。在更老的版本中是由master 線程完成。其執行幾個innodb的維護操做。刷寫過程不只能夠刷寫buffer pool,連innodb 的redo 和undo log也不會放過。 當事物在物理層寫入數據時,髒頁會被頻繁的更新。其本身的互斥機制保證了並不會鎖住整個buffer pool。 髒頁的最大數量取決於 innodb_max_dirty_pages_pct的設置,當達到最大限定時,髒頁會被刷寫。 innodb_flush_neighbor_pages決定了innodb如何選擇頁來刷寫。若是設置爲NONE,則只有選中的頁會被刷寫。若是是area,那麼臨近的頁也會被刷寫。若是是cont,全部連續的髒頁都會被刷寫. 關機過程當中,設置innodb_fast_shutdown=0會進行完整的頁刷新操做。通常來講應該是這樣,由於這樣會保證數據處於一致狀態。然而若是仍有許多變動還未寫入磁盤,那麼整個關機過程會很是慢,若是你想加速關機過程,能夠把此參數設置爲1或者2.可是這樣下次啓動時就會變慢。(原文並未交代具體參數的做用,如下摘自某貼: Innodb_fast_shutdown告訴innodb在它關閉的時候該作什麼工做。有三個值能夠選擇: 0表示在innodb關閉的時候,須要purge all, merge insert buffer,flush dirty pages。這是最慢的一種關閉方式,可是restart的時候也是最快的。 1表示在innodb關閉的時候,它不須要purge all,merge insert buffer,只須要flush dirty page。 2表示在innodb關閉的時候,它不須要purge all,merge insert buffer,也不進行flush dirty page,只將log buffer裏面的日誌flush到log files。所以等下進行恢復的時候它是最耗時的。 (拿oracle來對比,0表明了 shutdown immediately,完整,乾淨地關閉數據庫。2表明實例崩潰過程。再次重啓須要進行實例恢復過程) read ahead優化 read ahead 特性被設計用來減小磁盤的讀操做。它一次就讀取到那些可能會在將來被讀取到的數據。 有兩種算法來選擇提早讀取的頁 線性 read ahead 隨機 read ahead 線性 read ahead默認開啓。它會對buffer pool中順序讀取到的頁進行計數,若是數量超過或等於 innodb_read_ahead_threshold的值。則 innodb會從同一個extend中讀取全部的數據。innodb_read_ahead_threshold值必須只能被設置爲0到64之間的值。設置爲0關閉線性read ahead可是也不會開啓隨機read ahead。默認爲56. 隨機read ahead僅在innodb_random_read_ahead=ON時開啓。默認爲OFF。此算法會檢查buffer pool中是否有至少13個頁被讀取到同一extend中。此時不關心是不是順序讀取的。若是此變量開啓,那麼整個extend都會被讀取。13這個值沒法另行配置。 若是 innodb_read_ahead_threshold=0,且 innodb_random_read_ahead=OFF。則read ahead優化再也不使用。 buffer pool 性能診斷 mariadb提供了一些工具來監控buffer pool和innodb主線程的活動狀態。經過監控這些狀態,dba能夠調整相關參數以提高服務器性能。 本小節中,咱們將會討論 show engine innodb status 語句和 information-schema.innodb_buffer_pool_stats表。前者更易讀,後者更詳細。 innodb_buffer_pool_stats表包含一下幾列(不作翻譯): 這些值每次顯示都不一樣。 pages_mad_young_rate,pages_not_made_young_rate分別表明了變成new page和那些在必定時間內沒有被訪問到的old page的頻率(pages count /s)。若是前者值過高,則old 鏈可能不夠大。反之亦然。 read_ahead_rate和read_ahead_evicted_rate是兩個用來優化read ahead特性很是重要的參數。read_ahead_evicted_rate值應該比較小,由於它表示那些經過read ahead方式讀取到的可是無用的頁。若是這個值正常,可是read_ahead_rate很低。那麼極可能是read ahead讀到的內容不少都被用到了。若是使用的是線性read ahead,那麼能夠經過調整innodb_read_ahead_threshold參數進行優化。或者使用其餘算法。 以RATE後綴結尾的列,能夠表述服務器當前活動狀態。這些值應該在一天,整週或者整月屢次去檢查。能夠使用一些監控工具好比cacti或者nagios。percona monitoring tools包含了mariadb和mysql的插件爲這些工具提供監控接口。 導出和加載buffer pool 有些狀況下可能須要保存buffer pool當前的內容以便在之後須要的時候從新加載它們。最有可能的狀況就是服務器停機,隨後開啓。但此時buffer pool是空的,innodb須要填充進有用的數據。這個過程叫作warm-up.直到warm-up完成,innodb的性能都會比日常低。 兩個變量能夠幫咱們避免warm-up:innodb_buffer_pool_dump_at_shutdown和innodb_buffer_pool_load_at_startup。若是設置爲ON。innodb會在停機時自動保存buffer pool的內容到文件,在啓動時從文件中加載。這兩個變量默認爲OFF。 開啓它們頗有用,可是須要記住: 開機和停機時間可能會更長。若是有特別需求,自行斟酌 存儲buffer pool內容須要佔用必定磁盤空間。 用戶有時候會隨時導出buffer pool,而後不重啓數據庫直接恢復buffer pool的內容。這種操做建議在buffer pool已經處於優化狀態,可是隨後的操做會對buffer pool中的內容影響很大時進行。好比當對一張大的innodb表進行全表掃描時,邏輯備份時,都會把一些平時不怎麼訪問的數據填充到old list中。所以比較好的辦法就是提早備份出buffer pool,作完相關工做之後再把備份的buffer pool倒回去。 經過Innodb_buffer_pool_dump_status、Innodb_buffer_pool_load_status可查看dump/load的狀態.若是加載buffer pool花費了太長時間,能夠經過設置 innodb_buffer_pool_load_abort=ON來中斷導入過程。dump 文件的路徑和文件名能夠經過 innodb_buffer_pool_filename進行指定。須要確保有足夠的空間來存放dump文件,但其實用不了多大。 innodb change buffer. change buffer 屬於buffer pool中的一部分。其包含了與髒頁相關的二級索引內容。若是修改過的數據在後來被讀到,將會合併到buffer pool中。在老版本中,這個buffer 叫作insert buffer。後來更名了,由於它能夠支持更多操做類型的緩存。 change buffer 能夠加速如下幾個寫操做: insertions:當新行寫入 deletions:當存在的行被標記爲意圖刪除,但基於性能考慮還未真正進行物理刪除。 purges:物理刪除以前標記的行和索引。 這是由專用線程按期完成的。 有些狀況下,咱們想關掉change buffer。例如咱們有一個工做任務,只有關閉change buffer的時候內存大小才能知足要求。這種狀況下,即使關閉它,仍然須要頻繁地訪問buffer pool的二級索引。若是咱們的服務器不多進行DML操做,或者幾乎沒有二級索引,那麼關閉change buffer是個不錯的作法。 change buffer 能夠經過如下兩個變量進行配置: innodb_change_buffer_max_size:change buffer的最大大小。數值爲buffer pool的百分比。許可範圍爲0-50.默認爲25. innodb_change_buffering:定義何種操做使用change buffer。none(關閉全部buffer),all,insert,deletes,purges以及changes(包含inserts和deletes,不包括purges)。all爲默認值。 淺析 doublewrite buffer 當innodb把頁寫入磁盤時,至少兩個事件能夠中斷寫入操做:硬件錯誤或者系統錯誤。若是頁面不大於系統寫入的塊則不可能產生系統錯誤。 此時 innodb redo和undo 不足以恢復半寫的頁面,由於爲性能考慮,它只包含頁的id,但不包括數據。 爲避免半寫頁,innodb使用 doublewrite buffer.這種機制對每一個頁進行兩次寫入操做。只有第二次寫入成功,此頁纔算有效。當服務器重啓,若是進行恢復操做,半寫狀態的頁會被丟棄。doublewrite buffer會對性能影響不大,由於寫操做是順序進行,且是批量寫入的。 若是數據並不是很重要,也能夠關閉doublewrite buffer,經過設置innodb_doublewrite=OFF或者以 --skip-innodb-doublewrite參數啓動皆可。 若是性能問題很是重要,而且咱們使用的是快速存儲設備,根本不想給磁盤帶來任何額外負擔,哪怕一點點也不想。可是數據的準確性又十分重要,又不想直接關掉doublewrite buffer 機制。mariadb提供了另外一個叫作 atomic writes(原子寫入)的機制。這使得寫入操做就像事物同樣:要麼徹底成功,要麼徹底失敗。半寫狀態的數據不可能存在。然而mariadb並不會直接支持使用這種機制,須要使用FusionIO之類的存儲設備來實現。FusionIO閃存速度很是快。爲開啓這種原子寫入機制,能夠設置 innodb_use_atomic_writes=ON,開啓此功能會自動關閉doublewrite buffer。 MysISAM key cache MyISAM索引緩存在一個稱爲key cache或者key buffer 的數據結構中。此buffer能夠極大地減小物理索引文件的訪問。緩存的索引會在內存中被修改,會在隨後被刷寫到磁盤中。 key cache能夠關閉。mariadb中沒有對於數據的cache結構而是由操做系統自己進行緩存的。 若是禁用key cache,也是一樣的。 若是系統主要使用MYisam表,那麼key cache會變得很是大。不然,key cache能夠設置爲一個很是小的值。徹底關閉key cache是不可能的。若是內部臨時表使用的不是aria表(aria_used_for_temp_tables=OFF),那就是myisam了。 key cache大小由key_buffer_size變量控制。 key cache和myisam 索引文件同樣,由塊結構構成。一個塊是一小段連續的內存空間。索引文件和key cache能夠使用不一樣的塊大小。但最好爲最小內存塊大小的整數倍。索引文件塊和key cache塊大小能夠經過 myisam_block_size和key_cache_block_size變量控制。key cache 塊會在內存中被修改。所以,修改過的塊叫作髒塊,未修改過的叫作乾淨塊。 LRU和中點插入策略 默認狀況下,myisam使用LRU算法來判斷哪些blocks會被存放到cache中,若是key_cache_division_limit=100則使用此算法。純LRU算法有一個相似於InnoDB緩衝池解釋的問題。若是一個查詢作了完整索引掃描,它會訪問到那些不常常訪問的塊。這樣的塊會被放入到cache中,致使應該保留在cache中的塊被換出。 另外一種方法是將key cache存分爲兩個子列表:warm list 和 hot list。這些列表的長度不是變量,而是專用於warm list的key cache的最小百分比,由key_cache_division_limit變量決定,總保持warm list在這個百分比以上。(國內稱做 warm sub-chain 但原文仍叫作 warm list ) 當一個不在cache中的塊被訪問到時,它將插入到warm鏈表的尾端,其餘warm塊將向鏈表的末尾移動。 位於warm list開頭的塊會被首先換出。 若是一個warm list中的塊被訪問超過三次,它將會移動到hot list 的尾端。當其餘塊被插入到熱鏈表時,其餘塊會被移動到鏈表的尾端。若是hot list 頂部的塊在熱鏈表的尾端保留了一段時間,那麼它就又會被移到warm list中,保留的時間經過以下公式計算: blocks * key_cache_age_threshold / 100。blocks是cache中塊的數量,key_cache_age_threshold是系統變量。調大key_cache_age_threshold可讓塊在熱鏈表中保留更長的時間. 如下內容摘自網絡,寫的比原文更加詳細: (1) 該策略將前面的LRU隊列(LRU Chain)分紅兩部分,hot sub-chain和warm sub-chain。並根據參數key_cache_division_limit劃分,總保持warm sub-chain在這個百分比以上。默認狀況key_cache_division_limit是100,因此默認時候只有warm sub-chain,即LRU Chain。 (注:Multiple Key cache狀況,每一個key cache都有對應的key_cache_division_limit值) (2) 在warm sub-chain中的某個block若是被訪問(Access)次數超過某個值時候,就將該block放到hot sub-chain的底部。 (3) 在hot sub-chain中的block會隨着每一次的hit調整位置,hit越多,越接近底部。在頂部停留時間過長就會被降級到warm sub-chain中,並且是warm sub-chain的頂部(極可能很快就會被移出key cache)。 (4) Hot sub-chain中的頂部的block停留時間超過一個閾值後就會被降級到warm sub-chain。這個閾值由參數key_cache_age_threshold決定。具體的計算方法是:設N爲key cache中的block個數,若是在最近的(N*key_cache_age_threshold/100)次訪問中,key cache頂部的block仍然沒有被訪問到,那麼就會被移到warm sub-chain的頂部。 (5) 默認狀況key_cache_division_limit = 100,這時只有只有一個Chain,因此不使用該策略。即退化的Midpoint Insertion Strategy是LRU算法。 key cache 實例 在一些操做中,key cache由鎖來保護。此處有個問題就是多個鏈接同時訪問時會有衝突,有兩種機制能夠用來減小爭用:使用多個key cache實例和key cache段。每一個key cache實例有它本身的鎖。所以每一個實例都能單獨地進行配置。而默認的cache不能被移除或關閉。 默認狀況,只有一個默認的key cache實例存在,若是想增長更多的實例,能夠經過設置key_buffer_size變量進行建立。語法以下: SET [<instance_name>.]<variable_name>=<value>; 例如,爲了配置三個cache,包括默認的,運行以下命令: 沒有辦法查看全部的與非默認實例相關的變量(就是說show variables無用)。與實例相關的變量只能被獨立地查看。 須要記住,這些設置會在重啓時丟失。所以最好把配置信息寫入配置文件,好比這樣: 注意,配置文件中不能使用2000*6000這種表達式。 若是想看有哪些key cache以及相關信息,能夠經過查看 information_schema.key_caches表。好比這樣: 若是想關閉一個cache,設置它爲0便可: KEY_CACHE表包含如下幾列(不作翻譯): 若是一項任務的索引條目包含在key cache中,則讀取和寫入的數量,尤爲是等待讀取和寫入的數量在正常數據庫活動期間應該很是小。 大量未使用的塊表明了實例或段已經產生了碎片。單獨對一個實例或段進行碎片整理是不容許的。 每一個索引只能存放到一個key cache實例中。同一張表上的索引只能放到同一個cache中。若是與表關聯的cache沒有特別指定,則使用默認cache。所以若是隻有一個cache實例,那麼無需爲某張表特殊指定其餘cache。若是想把不一樣的cache與表進行關聯,須要使用cache index語句。這種創建的關聯關係是可變動的:能夠稍後將表從新分配給不一樣的cache。 基本示例: 上例中,myisam1和myisam2表被緩存到hot_key_cache實例中。 若是是分區表,那麼不一樣的分區能夠關聯進不一樣實例的cache中: ALL關鍵字表明瞭全部的分區必須被關聯到特定的cache中。此時partition子句能夠被省略。可是對應的key cache必須存在,不然報錯。 和實例配置同樣,服務器停機則表和cache實例的關聯關係就會解除。所以,cache index語句最好寫入到init文件中。init文件能夠經過配置文件中的 init-file選項進行配置,它在服務器啓動時執行。 key cache 段 另外一種減小衝突的方法是使用key cache 段。每個key cache是由幾個段組成的。爲使用此特性,能夠經過key_cache_segments變量進行配置。其表明了段的數量,最大爲64,最小爲0,表明關閉此特性。 正如以前所說。若是使用了key cache段。則information_schema.key_cache表中有些行是以不一樣段爲單位。而有些則是表明了整個cache實例,即使該實例一樣是配置過key cache段的。例子以下: 預先加載索引到cache中 如上例,咱們先關閉了段,那麼每一個cache實例只有一行。隨後咱們爲hot_key_cache開啓了段,這個cache實例仍然會存在一行,可是還會多出幾行同名的獨立段。咱們能夠經過unused_blocks大小輕鬆地判斷:每一個段大小都是4043,4個段加起來正好是一個實例大小:16172。 等待直到服務器正常活動讀取到索引塊時再加載它們到cache中會不大方便。因而咱們能夠在服務器啓動時預先加載索引到cache中。LOAD INDEX INTO CACHE語句能夠用來預加載全部表上的索引到其關聯的cache或者是默認的cache中。若是是分區表,那麼也能夠只預加載其中的一些分區索引,例如: 對於B樹索引,葉子節點會指向表中特定的行,若是那行記錄長時間沒有被訪問,那麼就無需緩存其相關的索引數據,這樣的緩存也不會有什麼好處,所以能夠經過 IGNORE LEAVES選項,放棄預加載葉子節點,只有在數據被訪問的時候纔會加載到cache中。若是key cache不足以放下整個索引,只能存放常常被訪問的部分,那麼這個選項將會很是有用。而且 它還具備減小加載操做時間的效果,示例以下: Aria page cache aria 把索引頁緩存在一種叫作 page cache的數據結構中。和myisam key cache很像,可是又多了一些其餘的特性。 本節主要講解兩種cache的數據結構不一樣以及如何使用page cache。 和myisam同樣,Aria索引按塊進行組織。塊的大小由 aria_block_size服務器變量進行控制。此變量會影響到索引文件和page cache,由於全部的塊大小必須相等。若是變量被更改,那麼全部的aria表須要重建。更改此變量須要進行如下步驟: 1 導出ariab表 2 關閉服務器 3 更改配置文件 4 重啓服務器 5 刪除或清空全部的aria表 6 從dump文件中還原數據 aria page cache 有且只有一個實例而且不能被分割。至於myisam中的其餘特性,則均可以被aria page cache支持,配置變量名稱和myisam的也很是類似。 page cache大小能夠經過 aria_pagecache_buffer_size變量配置。若是沒有使用aria表,這個值能夠設置爲0.記住,默認狀況下,aria表是用來作內部臨時表的。(--aria-used-for-temp-tables 啓動選項) LRU機制能夠經過aria_pagecache_division_limit和aria_pagecache_age_threshold變量配置,這兩個變量對應於 myisam上的 key_cache_division_limit和 key_cache_age_threshold。 因爲aria key cache不支持多實例和分段,所以也就不須要存儲統計信息到單獨地表中了。不過仍然能夠經過一些狀態變量來獲取aria的統計信息,好比下面這樣的查詢 show status like 'aria_page%'; 下面這張表展現了能夠返回哪些變量信息以及對應在key cache列中的變量值,其含義在前面已經講過,此處意義相同,不作贅述。 query cache query cache存儲了針對服務器執行的查詢和結果信息。若是用戶發起了一個查詢,正好這個查詢在cache中能夠找到,那麼結果就會當即被返回。固然,服務器仍舊會檢查當前帳戶是否有權限執行這個查詢。 query cache如何嚴重地影響服務器性能取決於負載狀況。在許多狀況下負載都能致使性能損失。query cache默認狀況下是開啓的,可是DBA仍舊須要根據具體的應用程序進行基準測試來決定是否啓用此功能。若是應用程序有所變更,那麼基準測試也應該按期重複進行。query cache也能夠根據需求激活它,也就是說query cache能夠關掉,可是若是特殊的指定了須要使用query cache的查詢,那麼該查詢仍舊會使用query cache。若是使用query cache對性能有負面影響,則此策略很是有用。可是能夠被cache大大加速的查詢就很是有限了。query cache經過互斥進行保護。互斥就是相互排斥(。。。原文確實有這句);就是一種鎖,mariadb用它來保證兩個線程不能同時訪問相同的資源——這裏的資源指的是cache。若是數據庫的併發性很高或者cache很大,那麼這種鎖就會拖慢數據庫速度。同時query cache也會使內存分配上更爲複雜,好比說爲了更爲重要的data或者key cache之類考慮就不得不把query cache配置得小一點。 任何對錶結構和數據的更改將會致使cache中與該表相關的query cache失效。 即便多個緩存的查詢包含許多結果,哪怕是對其中一個基礎表的最小更改也會使讀取它的全部查詢失效。若是一個無效的查詢能夠同時被多個鏈接執行,那麼多個鏈接將會嘗試再執行該查詢而且同時從新緩存相應數據。這種問題叫作 miss storm或者 cache stampede。 若是數據常常被更改,那麼query cache幾乎對性能沒什麼提高。若是數據不多被更改,好比僅在夜間或者一週變動一次,那麼配置query cache會使得查詢結果當即被返回。 在Galera 集羣和OQGRAPH存儲引擎使用時,query cache必須關閉。若是包含SPIDER表也應該避免使用,可是對於遠程服務器能夠配置。Galera第十二章的時候咱們再講,SPIDER第十一章會說到。 用戶發送到服務器的查詢語句僅在文本徹底匹配到cache中的內容時纔算命中。若是大小寫不一樣,空格甚至註釋之類有不一樣都會致使兩個查詢語句解析結果不一樣(和oracle同樣),好比這樣: 此外,僅當查詢使用相同的默認數據庫,默認字符集,SQL_MODE和協議版本時,查詢纔會匹配。 若是使用API(而不是PREPARE SQL語句)發送prepared 語句,則能夠對其進行高速緩存。prepared語句只能與其餘prepared 語句匹配,而且必須使用相同的參數.子查詢不會被緩存,可是它們有特殊的cache結構。 包含子查詢的外部查詢能夠被緩存。 如下幾種狀況查詢語句不會被緩存。 1 語句生成警告 2 存儲過程內部執行的 3 使用了臨時表或者用戶定義的變量 4 包含不定函數,存儲函數,或者UFDs 5 使用了系統表 6 若是使用瞭如下幾個子句:INTO OUTFILE,INTO DUMPFILE,LOCK IN SHARE MODE以及FOR UPDATE. 7 不涉及任何表,好比select version(); 8 引用的賬戶具備列級權限的表 9 使用了特殊的存儲引擎,好比spider這種。 若是 query cache開啓了,也能夠使用以下語法強制該查詢不被緩存 select SQL_NO_CACHE 若是query cache 關閉,能夠使用以下語法強制緩存該查詢 select SQL_CACHE query cache的內容會被服務器進行更改,一段時間以後內存就會產生碎片,爲解決此問題,能夠經過如下命令: FLUSH QUERY CACHE; 若是因爲一些緣由cache中存放了被無用的查詢語句緩存的內容,則能夠經過如下命令清空cache。 RESET QUERY CACHE; 配置query cache 若是使用了query cache,那麼配置它就顯得尤其重要。最好仍是反覆測試一下query cache對服務器性能的利弊。關於query cache的具體參數以下: 1 query_cache_type:開啓或關閉query cache。0或者OFF爲關閉,1或者ON爲開啓,2或者DEMAND僅在以前解釋的例子中啓用(就是能夠強顯式緩存某些語句)。若是是用在啓動選項中,則參數值必須爲數字。 2 query_cache_size:定義query cache大小。默認爲1MB。0表明關閉,可是此時還應指定query_cache_type以防止服務器檢查查詢是否可緩存,並使用互斥鎖保護緩存。不能配置過小的值,此值將四捨五入爲最接近的1,024的倍數。 3 query_cache_alloc_block_size:cache中使用的內存塊大小。此值能夠被隨時更改。大一點能夠減小碎片化保證緩存速度更快,可是也會浪費一些內存。 4 query_cache_limit:限制最大能夠緩存的查詢結果集的大小。若是一個查詢返回的結果太大,則不會被緩存,此變量很是重要,由於它會阻止少許的大結果集查詢來浪費cache。 5 query_cache_strip_comments:此變量設置爲ON那麼會致使查詢在緩存以前會刪除提示。此時不一樣提示可是其他相同的查詢算作匹配的。注意,若是使用的客戶端或API的進行剝離註釋,則非必須。 query cache狀態 若是想得到query cache的狀態信息,則能夠經過以下操做完成 QCACHE_FREE_BLOCKS和Qcache_free_memory表明了空閒內存數,計量單位爲塊和bytes。若是query cache使用率很是高可是這兩個值不高,說明cache中產生了碎片,此時應使用FLUSH QUERY CACHE進行碎片整理。 Qcache_total_blocks表明了內存塊的總數,包括使用的和沒使用的。 Query cache使用可變大小的塊 Qcache_hits:表明了用戶發起的查詢語句與cache中緩存的語句的匹配狀況,即命中率,應該保證此值很是高或處於增加狀態。 Qcache_inserts:表明添加的cache中的條目數 Qcache_lowmem_prunes:從cache中刪除的條目數, 若是這些值很高,查詢緩存的效率會下降。 Qcache_not_cached:不能被緩存的查詢語句的數量 Qcache_queries_in_cache:當前緩存的語句的數量。 mariadb一樣提供了 query_cache_info 插件。此插件默認未開啓,能夠經過如下命令安裝: 一旦安裝完畢,query_cache_info表就會被添加到 information_scheam數據庫中。其存儲了query cache中的條目信息,包含以下幾列: 1 statement_schema:當語句執行時選擇的數據庫 2 statement_text:緩存的查詢語句 3 result_blocks_count:存儲結果集的內存塊的數量 4 result_blocks_size: 內存塊的大小 5 result_blocks_size_used:存儲結果集的內存總量 如今,咱們將會看一個例子,首先清空cache,咱們執行show status語句並使用空的query cache來查詢query_cache_info表。隨後咱們執行一個簡單的查詢並執行一樣的操做觀察一些細微的變化。操做以下: subquery cache 正如以前全部,子查詢會被緩存到一個獨立地數據結構中——subquery cache。 若是某些子查詢出如今不一樣的外部查詢中,這是很是有用的,subquery cache在mariadb5.2中引入,而且默認開啓。若是想關閉能夠使用以下命令: SET @@global.optimizer_swithc='subquery_cache=off'; 有兩個狀態變量提供了關於subquery cache的效率信息。subquery_cache_hit變量表明cache命中的子查詢的數量。subquery_cache_miss變量則是沒有命中的數量。命中率根據如下公式計算: 對於每個須要被緩存的子查詢都會建立一張memory 臨時表。這張表會存儲子查詢的結果集及其參數。如用來排序和分組的內部臨時表同樣,subquery cache表受 tmp_table_size和max_heap_table_size系統變量影響。若是超過其中任何一個變量的限制。cache的具體行爲取決於命中率,若是命中率小於0.2,則關閉cache。若是小於0.7,則memory表被清空可是其結構得以保存並會在之後從新填充。若是大於0.7則表會寫入磁盤。 替代查詢緩存方法 有個query cache的問題就是對錶的頻繁更改會讓緩存的查詢無效,使得性能難以預測而且會致使cache stampedes。所以,取決於負載,咱們想採用一種query cache的替代方法。 有時候不多的結果集會形成很高昂的開銷。典型的例子就是在大表中使用聚合函數。這樣的查詢一般生成統計數據,而且可能不須要老是隨時更新。例如,若是一個查詢關聯了全部以月份爲分組的彙集數據(好比上個月的銷售狀況),這樣的結果對包含今天的數據並不重要(有時甚至是一週或者一個月)。這種狀況下,工做負載可能受益於彙總表,彙總表就是按期清空並使用查詢結果從新填充的表。填充彙總表可能很是慢,可是查詢該表則很是快。 把全部數據彙集到一張彙總表中可能就足夠了,不一樣的查詢檢索其中的一部分數據。或者能夠把不一樣的結果集存放到不一樣的表中,再或者混合使用上述兩種策略。 在許多狀況下,查詢生成html報告或xml文檔。其中的一些報告並不會每小時或天天進行變動。或者即使有變動也是不相關的內容。若是報告預計在一段時間內保持不變或被容許這樣作,那麼整個報告能夠被緩存到表中。這能夠提升應用程序效率,特別是若是更新報告會涉及昂貴的查詢的時候。 通常來講memory表是最佳的選擇。固然,若是服務器崩潰數據則會丟失,可是表能夠從新填充,由於非彙集的數據已經都寫入了磁盤。還有另外一種用來存儲彙總數據或者報告的方法就是使用key-value軟件,這些軟件對於此類查詢進行了優化。最多見的就是memcached。其優勢之一就是能夠對存儲的值設置超時時間。這容許咱們在存儲在基礎數據更改時未失效的過期數據,可是在給定的時間後會自動消失。 然而,當數據到期時,可能發生cache stampede的問題。所以對於許多負載狀況,這樣的方案並不能解決query cache中的主要問題。 table open cache 當線程須要訪問表的物理文件時會須要一個文件描述符。爲加速文件訪問,mariadb會緩存這個文件描述符到table open cache中。若是同一數據庫中包含了許多myisam表時會很是有用。在cache中搜索一個文件描述符是會產生開銷的。若是緩存不足夠大以放下全部須要的文件描述符,那麼最好關閉它。DBA最好作一些測試來決定table open cache是否適用於當前的負載狀況。 table_open_cache服務器變量決定了能夠緩存多少個文件描述符。這個值不要超過操做系統中容許的最大文件打開數量,不然服務器會拒絕新的鏈接。在unix系統上,這個值能夠經過以下命令得到 ulimit -n 別的系統上,若是ulimit命令不可用,那麼就去查看系統文檔。 對於緩存全部須要的文件描述符的數量,table_open_cache應該等於容許的最大鏈接數(max_connections變量)*包含關聯最多表的查詢語句涉及到的表的數量。另外別忘了再加上一些臨時表。對於myisam和ariab表會緩存其索引文件的文件描述符,可是這些描述符能夠被全部鏈接所共享。 若是服務器報出了不能打開更多文件的錯誤,極可能是 mysqld_safe --open-files-limit啓動選項設置的太小。 per-session buffers mariadb有幾個per-session buffer以加速一些查詢。若是這些值過小,一些複雜的查詢則會花費很長時間。若是設置的很是大,那麼在大併發狀況下又會浪費大量內存。DBA應該根據業務把該參數控制在合理範圍以內。 當應用程序打開一個鏈接的時候,應該大體知道發起的是何種語句。極可能不一樣的應用程序鏈接執行的是不一樣的任務。好比web應用程序那種,大多數鏈接執行一些簡單查詢,還有一些執行更復雜的任務,也就須要更多的資源。 per-session buffer 能夠基於每一個會話單獨配置:一個鏈接能夠改變該值大小而不至於影響其餘鏈接。也就是說它容許爲一些會話配置大的緩存,爲一些簡單的查詢配置小一點的緩存。 在會話級配置 per-session buffer,鏈接須要發起以下命令: 若是爲全部鏈接設置默認值,操做以下: 可是,即使很好地配置了該參數,內存依舊會在許多鏈接不須要該緩存而又不及時關閉的狀況下產生浪費。開發人員應該確保鏈接在不須要的時候及時地關閉。或者設置一個會話超時時間。當鏈接空閒時,在必定時間後關閉該鏈接。此時間能夠經過wait_timeout參數進行配置。若是他們超過必定數量,咱們也能夠強制服務器拒絕鏈接,此數量由max_connections進行控制。爲此變量設置適當的值能夠保證服務器免遭拒絕服務攻擊。可是在作此工做以前咱們必須明本身的工做負載狀況,以防一些用戶沒法鏈接到數據庫。 如下幾個參數影響了per-session buffer的行爲 1 sort_buffer_size:用以加速order by。若是show session status展現的sort_merge_passes過高,則說明此值過小。 2 read_buffer_size:優化myisam表的順序掃描 3 read_rnd_buffer_size: 加快了使用多範圍優化策略執行的查詢和從MyISAM表的全部隨機讀取。 4 join_buffer_size:使用batched key訪問策略優化join 5 bulk_insert_buffer_size:加速多行插入(包括load data infile)到myisam表。 總結: 本章咱們討論了mariadb的緩存。最重要的就是存儲引擎使用的緩存。咱們用了大量筆墨描述了innodb buffer pool,由於它更復雜也更經常使用。innodb buffer pool會緩存數據和索引,myisam和aria只緩存索引。 query cache有時是一個很是有用的解決方法,由於它能夠當即返回須要的結果集。一樣,subquery cache可讓子查詢當即返回結果集。然而在典型的OLTP中,數據常常會失效,因此是否使用有待商榷。咱們還學習到,此cache很是有用可是須要dba進行反覆測試以保證可用。咱們 還討論了query cache的替代方案。 還討論了table open cache,此cache用來避免服務器太過頻繁地打開關閉文件。 在最後一節,討論了關於per-session buffer的內容。 下一章咱們會介紹innodb 表壓縮技術,以及如何在緩衝池中處理壓縮數據。 第七章 innodb 表壓縮 大多數數據庫都有一個共同的特性:數據都是增加的。一般意味着這個庫的價值愈來愈高,對用戶也愈來愈有用。可是這也會致使一些問題。本章將會講解用來減少數據庫的物理文件體積的特性:innodb表壓縮。 innodb無需使用特殊工具,僅經過sql語句便可完成表壓縮過程。壓縮過的表和未壓縮的同樣,能夠正常讀取寫入數據。這個特性能不能提高性能還很差說,但有一點是確定的——它節省了磁盤空間。 本章涉及如下幾點: 1 使用innodb壓縮前提 2 建立innodb壓縮表 3 實施壓縮 4 監控壓縮表性能 5 其餘的壓縮解決方案 innodb 壓縮技術概述 innodb支持表壓縮技術,使用這種技術通常基於如下兩點考慮 1 節省磁盤空間 2 減小I/O 若是咱們使用的是SSD,那麼第一個緣由很是重要,畢竟太多的I/O會減小SSD的壽命. 在許多負載中,磁盤的I/O會是性能的瓶頸.減小數據文件體積能夠明顯減小須要把數據從磁盤讀取到buffer pool中的I/O次數,反之亦然. 然而,innodb壓縮技術會有一些開銷。從磁盤中讀取的頁在加載到內存以前須要先進行解壓。內存中被修改的數據在寫回磁盤以前須要進行壓縮。所以會對CPU產生負擔。故使用壓縮技術會使性能降低。 若是內存足夠,innodb會在buffer pool中保存壓縮過和未壓縮過的兩個版本的數據。這就意味着要麼buffer pool足夠大,要麼數據足夠小。 In this case, useful pages can be evicted from the buffer pool so that it contains compressed pages(這句話做者寫的先後不搭,也可有可無。)所以,innodb壓縮技術在讀繁重的服務器上有優點,而在寫繁重的服務器上,最好不要使用。 還有個重要問題就是要壓縮表數據的效果。innodb使用LZ77算法進行壓縮。這種算法很是適合文本類型數據,對數字效果通常,對於已經壓縮過的數據格式,好比圖片,mp3,視頻沒有效果。 對於TEXT,BLOB,VARCHAR類型的數據,有必要的話最好單獨存放。若是一個頁面不能放下一行數據的話,那麼最大的列將會被移動到一個叫作overflow pages的特殊結構的頁。移動這樣的頁將會影響到全部的操做。若是使用表壓縮技術能夠減小overflow pages的數量,那麼使用它是最好不過的了。 熟悉innodb壓縮技術是很是重要的,惟一一種判斷該技術是否適用於當前工做負載的辦法就是去測試它。要基於真實的負載狀況,而且經過監測一些 information_schema表。 使用innodb壓縮前提 爲了使用innodb 壓縮技術,有兩點硬性要求須要知足。 1 每張表必須存儲在單獨的文件中 2 必須使用 Barracuda文件格式 下面咱們開始討論具體內容以及如何實現。、 淺析 file-per-table 模式 innodb表存儲在表空間中,其包含了數據和索引,在老版本的MariaDB中,默認狀況下,innodb只使用一個表空間——系統表空間。它同時也包含了change buffer,doublewirte buffer以及undo 日誌。這個表空間存放在MariaDB定義的數據目錄中的ibdata文件中。然而在最新版的MariaDB中,系統表空間仍然能夠存放這些,可是最新系統支持每張表單獨存放到一個表空間中,在建立表的同時會建立出相應的以.ibd爲擴展名的表空間文件。存放在datadir中(注意數據庫目錄存放在datadir中,是datadir的一個子文件夾)。這種存儲方式叫作file-per-table模式。MariaDB 10 中默認開啓。 file-per-table默認開啓,若是想關閉它,能夠設置 innodb_file_per_table變量。當表被建立時,innodb會校驗該變量以決定是存放到系統表空間仍是單獨地表空間中。 讓咱們看個示例,在MariaDB中建立一些表: 如今,來查看一下datadir和數據庫目錄的內容 除了能夠看到系統表空間,在test_innodb文件夾中能夠看到 1 數據庫選項文件db.opt 2 表結構定義文件 .frm 3 do.ibd表空間文件 當建立haon和tri表的時候,innodb_file_per_table=off,這兩張表會存放到系統表空間中並不會爲它們建立單獨地表空間。當建立do表的時候,innodb_file_per_table=ON,所以會有一個單獨地do.ibd表空間文件。 innodb文件格式簡述 innodb很早以前使用一種叫作 Antelope的文件格式。爲向後兼容考慮,新版本中仍舊兼容此格式。系統表空間使用此格式。新版本中出現了Barracuda文件格式,其支持更多特性。表壓縮技術只能在Barracuda文件格式上使用。 //*兩個文件格式名字源於英文單詞表的字母。新的表格式仍舊會保持這種命名規則,即下一版是以E開頭的動物名稱命名(C去哪兒了)*// 當 file-per_table 模式開啓且建立新表時,innodb會根據innodb_file_format變量決定建立表的文件格式。在information_schema數據庫中的 innodb_sys_tables 和 innodb_sys_tablespaces表中有一列叫作 FILE_FORMAT,其表明具體表使用的具體文件格式。 看一個建立兩種不一樣文件格式的表的例子: 不一樣的文件格式表明着不一樣的行格式。爲使用barracuda,咱們在建立表時必須特別聲名行格式是 DYNAMIC仍是COMPRESSED。默認行格式是COMPACT,是Antelope文件格式定義的行格式,若是行格式是這個,說明沒有使用 Barracuda。 //*若是是在MySQL或者MariaDB 5.5版本以前使用複製環境,則須要去設定innodb_file_format=‘Antelope’,確保沒有表使用 Barracuda。 *// 如今來查看 INNODB_SYS_TABLESPACES表: 當使用 antelope格式時,information_schema中的表不會告訴咱們表到底使用了什麼行格式(很明顯,最開始定義這個格式的時候還沒料到後面會出現新格式)。若是是用了Barracuda的壓縮表,則在ROW_FORMAT列中出現的應該是COMPRESSED. //*表能夠在系統表空間和本身獨立地表空間之間互相移動,這個時候就須要注意 innodb_file_per_table和innodb_file_format的設置,在發起alter table命令時須要尤爲當心。此兩個變量僅存於全局變量中。這就表示有必定的風險,若是當前鏈接並非惟一擁有SUPER權限的鏈接。謹防一個線程更改變量,同時另外一個線程操做alter table這種狀況發生。*// barracuda文件格式在MariaDB 5.5和mysql5.5時引入,也就是說,若是使用複製環境,某一端版本早於5.5以前的話,不能使用barracuda格式,也不能使用壓縮特性。 建立innodb 壓縮表 在建立壓縮表以前,一般最好確認一下服務器的SQL_MODE是否處於strict 模式,理由是若是處於strict模式,innodb會更詳細地檢查create table語句。若是有些表定義寫錯了,表就不會建立而且拋出錯誤。這會防止咱們由於手抖建立出意料以外的表結構。可是,已存在的應用會依賴於現有的sql語句,若是在strict模式,可能會阻礙應用程序正常運行。所以,strict模式默認是關閉的,而且使用時最好在會話級開啓。若是想全局開啓innodb的strict模式,執行以下命令: SET @@GLOBAL.INNODB_STRICT_MODE=ON; //* 在當前版本中,用strict 模式來檢查建立壓縮表的步驟是惟一會用到的地方。可是,在將來的版本中,它可能會用在更多的地方,不只僅是建立表。所以,除非它會致使咱們應用程序產生錯誤,不然最好仍是一直開啓 *// 在檢查了 INNODB_FILE_PER_TABLE和INNODB_FILE_FORMAT變量以後,咱們就能夠開始建立innodb壓縮表了。很簡單,在建表語句後面跟着COMPRESSED子句便可 對於壓縮表,索引塊的大小能夠根據每張表進行單獨配置。經過使用KEY_BLOCK_SIZE選項便可。此選項僅在使用壓縮表時有效,所以,若是使用了這個選項,那麼COMPRESSED子句就能夠忽略掉了。 索引塊的大小不會影響到表的壓縮級別,壓縮級別不能根據每張表單獨進行設置。然而經過更改頁大小,咱們能夠決定一頁能夠存放多少行數據。容許的值爲 16K,8K(默認),4K,2k和1K。0表明默認值,可是在這樣設置,就不會使用表壓縮了。一般KEY_BLOCK_SIZE會小於INNODB_PAGE_SIZE(默認16K)。然而,若是表包含TEXT或者BLOB列, 一個16 KB的內存可能容許在常規頁中存儲許多值,所以它們不會存儲在offset pages偏移頁中(如第6章緩存中所述) 有時咱們會設置一個不符合要求的KEY_BLOCK_SIZE值。這種狀況下,innodb的strict模式處於開啓狀態則尤其重要,由於它會強制MariaDB報錯。若是沒有開啓該模式,表就會被建立,可是隨後在插入數據或者update的時候就會報錯。 選出最佳的KEY_BLOCK_SIZE值就是建立數據相同結構相同可是KEY_BLOCK_SIZE不一樣的多張表,而後基於真實的負載狀況進行性能測試。壓縮表的性能能夠經過查詢information_schema數據庫,本章隨後即說到。 能夠經過命令來更改壓縮表的KEY_BLOCK_SIZE,好比這樣: ALTER TABLE COM_TABLE KEY_BLOCK_SIZE=16; 甚至能夠將一個未壓縮過的表變爲壓縮表: 上面兩個alter table命令須要花費點時間可是由於使用 IN-PLACE算法,不會產生鎖定。 INNODB 壓縮表實施參數簡述 經過設置 INNODB_COMPRESSION_LEVEL變量能夠改變壓縮表的壓縮級別,可選參數爲0-9 的整數。值越高表明壓縮效果越好,可是性能也就越差。默認的壓縮級別爲 6,此變量動態可調整。 正如以前所說,當索引條目從磁盤讀取到buffer pool的時候,其會包含壓縮的和未壓縮的兩份數據結構。innodb 經過幾種辦法來避免大量的壓縮和解壓縮操做。好比,它在修改了一個壓縮的頁面的數據,並不當即壓縮,而是在頁面須要刷寫到磁盤時再進行壓縮。爲達到這種目的,使用了一種叫作 modification log的日誌結構來跟蹤這些須要壓縮但還未壓縮的塊。常常更新和插入較短的行能夠不用重組頁面便可完成。 須要說明的是,每一個頁面的 modification log都有空間限制。若是innodb嘗試寫入change到日誌中,可是又無空間可用,頁面又未通過壓縮,那麼記錄的變動會被應用,而且頁面會被再次壓縮。在某些狀況下,頁面會在某些變動發生後變得很是大,此時數據須要重組以適應頁大小。當新的頁仍舊過大的時候,就會發生 compression failure錯誤. 重建壓縮頁會耗費時間,所以innodb儘可能去避免頻繁地出現compression failures。若是compression failure和應用變動之間的比率超過innodb_compression_failure_threshold_pct設置的值,innodb會在每一個新的壓縮的頁的末尾留一段空餘空間。 innodb_compression_failure_threshold_pct服務器變量是一個百分比值,默認爲5. innodb_compression_pad_pct_max 服務器變量指定了每一個壓縮頁保留空餘空間的最大百分比。許可範圍爲0-75,默認是50.若是設置爲0,則表示關閉此項功能。(表示不留空,注意是留空百分比。) 若是compression failures在某張表上發生的太過頻繁,說明對應的 KEY_BLOCK_SIZE可能設置的過小。若是壓縮表的性能很低而且常常發生compression failures,那麼最好適當調大innodb_compression_failure_threshold_pct的比率。 若是常規的更新會顯著增長行的大小,那麼應該把 innodb_compression_pad_pct_max設置的大一些. 下一節將會講解若是監控壓縮表的性能 監控壓縮表性能: information_schema數據庫中有些表能夠用來監控innodb壓縮表的性能。全部與之相關的表都以 innodb_cmp開頭,所以能夠經過如下語句列出相關表. 主要的innodb表有: 1 INNODB_CMPMEM:存儲在buffer pool中關於壓縮表頁面的數據 2 INNODB_CMP:存儲整個服務器有關壓縮和未壓縮操做的相關內容。 3 INNODB_CMP_PER_INDEX:此表內容和上一張很是相似,只不過是經過每張表和索引進行分組列出。下圖我未使用壓縮表。因此都是0. 還有一些以_RESET結尾的表,對應着前半部分名字相同的表,與以前不一樣的是,這種表只要一被查詢,則以前對應的表內容就會被重置。此能夠用來在一段時間內監控壓縮表的性能變化狀況。或者用來檢查變量變動先後的影響。 //* 查看 innodb_cmp_per_index和innod_cmp_per_index_reset表會對性能形成很大影響,所以通常都是空的,除非設置了 innodb_cmp_per_index_enable=ON,不過建議在生產環境最好不要這麼幹. *// INNODB_CMPMEM表: 此表展現了buffer pool中的壓縮頁的統計數據。數據以頁大小爲分組。每行展現了不一樣的KEY_BLOCK_SIZE大小的表的狀態。事實上,如此設計都是爲DBA方便來決定每張表的KEY_BLOCK_SIZE大小的。下面這張表展現了 INNODB_CMPMEM表的列含義(不作翻譯): 當INNODB_CMPMEM_RESET表被讀取的時候,RELOCATION_OPS和RELOCATION_TIMES字段會被置0。 假定咱們有一張customer表,經過該表結構建立三張以不一樣KEY_BLOCK_SIZE大小,經過名稱予以區分的表:custumers_16,customers_8以及customers_4.如以前所說,優秀的測試源於真實的負載狀況。然而,在本例中,咱們僅僅來看這些表若是工做,所以咱們只執行select count(*) 來查看每張表。隨後,咱們將會查看 innodb_cmpmem_reset.示例以下: 在進行真實測試和檢查過這些表的內容以後,咱們將會選擇一個比較小的KEY_BLOCK_SIZE,由於它不須要太多的從新申請內存的操做。 INNODB_CMP_PER_INDEX表 INNODB_CMP_PER_INDEX表以索引爲分組展現了壓縮頁的性能信息。如以前所說,查詢該表開銷很大,所以INNODB_CMP_PER_INDEX總爲空,除非INNODB_CMP_PER_INDEX_ENABLED=ON。 該表包含如下幾列: 1 DATABASE_NAME:不用說吧 2 TABLE_NAME :也不用說吧 3 INDEX_NAME:更不用說吧,這張表就是基於索引進行group by的。 4 COMPRESS_OPS:modification log 中的變動應用到頁面的次數 5 COMPRESS_OPS_OK:壓縮操做成功的次數 6 COMPRESS_TIME:壓縮數據耗費的時間 7 UNCOMPRESS_OPS:解壓操做的次數。記住此數值不斷增加,新的索引條目讀取到buffer pool和壓縮操做失敗都會增長此數字 8 UNCOMPRESS_TIME :解壓操做耗費的時間 當讀取 INNODM_CMP_PER_INDEX_RESET表的時候,除了 DATABASE_NAME,TABLE_NAME,和INDEX_NAME列外所有置0. //* 此表告訴咱們多少索引會受壓縮,解壓縮操做產生性能的負面影響。壓縮失敗的次數不一樣於COMPRESS_OPS和COMPRESS_OPS_OK.若是該值過高,則性能太差,索引速度會減慢,由於頁面會被常常寫入,換出buffer pool。若是buffer pool配置和索引使用狀況沒有得以改善,則表將不會被壓縮。 若是壓縮失敗太多,應嘗試減小該狀況。若是壓縮失敗發生在一張表或者一個索引上,咱們應該考慮修改 KEY_BLOCK_SIZE選項;另外一方面,咱們能夠嘗試設置恰當的INNODB_COMPRESSION_FAILURE_THRESHOLD_PCT和INNODB_COMPRESSION_PAD_PCT_MAX選項 *// INNODB_CMP表 此表和INNODB_CMP_PER_INDEX表基本相同,區別之處就在不是以索引爲分組。此表不多用到,可是由於收集該數據耗費不了什麼資源,因此此表總不爲空。 INNODB_CMP表和INNODB_CMP_PER_INDEX表有着相同的列,惟一不一樣之處就是沒有DATABASE_NAME,TABLE_NAME,INDEX_NAME列. 若是查詢INNODB_CMP_RESET表,則它的內容會被重置. 其餘壓縮方案 有些存儲引擎也能壓縮表,好比這些: 1: ToKuDB:其上的表老是被壓縮。這就是該引擎的特性。其專一於經過大量減小磁盤操寫入操做提高性能。 2:ARCHIVE: 專爲壓縮表設計,可是功能有限,能夠插入數據,不可刪除和修改,索引支持也很是有限。 3 :MyISAM:普通表不會被壓縮,須要經過特殊的工具——myisampack來壓縮表。而且壓縮事後只支持讀取 //* Aria引擎功能比Myisam更強大,但它不支持壓縮 *// 其餘的壓縮方案超出本書範圍,而且也不像innodb使用的那麼頻繁,好比tukudb,在不少負載狀況下都不如innodb性能高。archive引擎和myisampack工具很是容易使用,可是在大多數狀況下,由於限制太多達不到技術要求。雖然tokudb引擎在壓縮方面一樣具備很強的靈活性。然而tokudb並不是是一兩句能說清楚的,而且默認並不開啓,本書不涉及此內容。 可是做爲DBA,知道這些東西存在仍是頗有必要的,下例中展現了不一樣引擎下的不一樣的壓縮表的狀況: 上面的輸出已經經過格式化展現以方便閱讀,可是結果是真實的。固然, 有時候咱們會獲得徹底不一樣的結果, 因此若是與咱們的生產環境狀況相關,最好提早作好的測試。可是該表內容仍舊錶明瞭一類真實狀況:包含許多短的文本字段,自動提交鍵,以及相應索引。 上例中的數據文件以下: 1 customers_non_comp.ibd:innodb表,但沒壓縮 2 customers_*.ibd: 經過不一樣的KEY_BLOCK_SZIE進行壓縮的innodb表 3 customers_arch.arz ARCHIVE 表 4 customers_myi.myd 和 customers_myi.myi:壓縮過的myisam數據和索引 在這個例子中,壓縮過的myisam文件會比壓縮得最好得innodb表空間還大一點,最終archive壓縮效果最好.(他說的是myisam的數據+索引的體積) 能夠看出archive和innodb的壓縮比很高,而後咱們就得出結論使用archive是最好得選擇了嗎?NO!看如下幾個緣由解釋爲何innodb這麼有用: 1 archive 不支持事物,不過對於大表作OLAP不錯 2 innodb 插入性能很是好,Xtradb更好 3 archive不支持像 LINESTRING或者POLYGON這樣的geometric數據類型 4 壓縮表雖然不會常常被讀取,可是咱們仍是想加上索引,archive只支持給主鍵是自增列的列增長索引其他不支持。 5 innodb和xtradb的開發者很活躍,archive有點疲軟 若是以上緣由都不是主要緣由,那麼archive是個不錯的選擇。至於其餘狀況,調整innodb_comperssion_level是個比使用archive更好的辦法。 總結: 本章咱們討論了innodb表壓縮技術。包括在哪一種場景下使用,以及是否真的適用於咱們的負載狀況。 咱們學習了若是建立壓縮表和配置innodb壓縮參數。而後。咱們討論瞭如何監控innodb壓縮表性能。 在討論這些內容的同時,咱們還介紹了innodb其餘的重要特性:file-per-table(每張表自成一個表空間文件)模式和innodb文件格式(僅有barracuda格式能夠使用壓縮表) MariaDB還提供了一些其餘很是有用存儲引擎。所以在最後的部分,咱們比較了innodb壓縮方案和其餘引擎的方案。 下一章中,咱們將會討論備份和恢復技術,以及如何應對數據損毀。 第八章 備份和災難恢復 現在,愈來愈多的商業系統,包括企業活動,營銷流程基本上都須要經過應用程序來操做數據庫中的記錄。若是發生數據丟失,那麼公司的一些正常活動可能就會停止,除非數據正常恢復。若是數據丟失不可復原。公司極可能由於丟失數據而形成巨大的損失。這種數據丟失對公司來講稱之爲災難一點也不爲過。用行話來說,儘量地恢復這些數據叫作災難恢復。由於並非總能恢復得了數據,所以很是有必要去制定數據備份策略以便在災難發生以後迅速準確地進行恢復。本章將會講解備份和災難恢復。這對DBA來講是一項十分重要的工做。 本章將會涉及如下幾個主題: 1 備份類型 2 經過mysqldump進行邏輯備份 3 經過文件系統進行物理備份 4 經過 percona xtrabackup進行完整和增量備份 5 如何還原 6 如何修復損壞表 備份類型 有些問題會致使數據損毀或丟失,緣由有如下幾種可能: 1 磁盤寫入時忽然斷電 2 硬件錯誤(好比磁盤或主板) 3 操做系統崩潰 4 MariaDB或存儲引擎BUG(和別的程序同樣,MariaDB也有bug) 人爲也會致使發生數據損毀。好比黑客使用軟件漏洞來摧毀數據。或者多是咱們手殘敲了 DROP DATABASE刪了不想刪的庫。 沒辦法確保這些事故絕對不會發生,相反,有可能發生的就必定會發生。所以咱們須要經過備份數據來時刻準備着還原那些重要的數據。 能夠經過幾種方法來進行備份。其中各有所長,無一獨大。選擇哪一種備份要取決於不少因素。在制定備份計劃以前,咱們須要考察以下幾個問題: 1 數據的重要性 2 數據更新頻率 3 是否能夠在備份過程當中臨時停機? 根據需求,咱們才能清晰地去選擇最適用於咱們的備份策略。 邏輯和物理備份 邏輯備份會建立相關數據的備份文件。好比CSV格式的文件會包括全部的值,text類型的會包含大量的重建相關數據須要的SQL語句。它們統稱爲dump文件 物理備份指的是從物理級別複製數據文件。要求就是在備份完成以前,MariaDB不能往相關文件寫入任何數據。這對於myisam這樣的存儲引擎來說還好說,可是對於結構複雜的innodb,則很難實現。在mariadb10以前的版本中,想要備份innodb表,就不得不完整停機。物理備份會複製整個數據目錄。默認狀況下會包含日誌和配置文件。 有些存儲引擎,好比myisam,把表都存放到一個文件中;其餘的則不是,好比第七章咱們說到的innodb能夠把每張表單獨存放到一個文件中。若是表被分散存放,就能夠只備份有關聯的數據,而不是全部表。這對於在有些不多(幾乎不會有)變動的表或者能夠輕鬆經過其餘表進行重建的表來講很是實用。 對於分區表,每一個分區都會存儲在一個單獨的文件中。通常最新的分區包含了最近的數據,而其餘分區包含歷史數據。例如,某個分區存放着上個月發生的交易記錄,其餘分區存放着更老的記錄。由於歷史數據咱們以前確定備份過了,所以如今只須要備份一個最新的分區便可。分區咱們在第十章再說。 邏輯備份要點 1 數據庫不須要完整關閉。然而,繁重的事物會影響事物表性能,非事物表會被鎖定。所以此種備份一般會由於密集的讀操做而減慢服務器性能 2 邏輯備份靈活多變,定製起來很是容易。好比,能夠在恢復數據以前經過修改dump文件來變動數據庫的名字。或者能夠刪除其中的一些行。 3 邏輯備份比物理備份的選擇性更強。它基於sql語句,能夠經過複製語句來控制一些行或列。 4 邏輯備份能夠恢復到MariaDB更老的版本上去。好比,在升級MariaDB時應該建立一個邏輯備份以備發生錯誤。 物理備份要點 1 物理備份速度更快,由於它直接經過操做系統進行復制。體積一般也比較小,由於其包含的數據和索引已是緊湊排列的。 2 物理備份一般須要包括日誌和配置文件。雖然不是恢復數據的必備,可是若是丟失了配置文件和重要的日誌應該也算得上一種災難吧。 熱備和冷備 定義:服務器運行時進行的備份叫作熱備,停機時進行的備份叫作冷備 全部的邏輯備份都是熱備。沒法經過不檢索MariaDB數據來進行邏輯備份 對於MariaDB 10來講,能夠在備份期間鎖定物理文件,所以無需中止服務器。然而對於老版本,對於innodb文件只能進行冷備。在熱備期間,服務器仍舊能夠接收來自客戶端的命令。 可是咱們知道備份會花費不少時間,而且會把客戶端的請求進行隊列處理。或者若是容許服務器在一段時間內停機,好比說下班後。此時,若是咱們想進行物理備份,咱們更傾向停機進行備份。一來無需中止鎖表,二來整個過程會更直接。 完整和增量備份 若是須要備份的數據量很是大,那麼備份會花費很長時間,在整個備份期間,表極可能會被鎖定。同時備份也須要大量空間。爲減小備份時間和佔用的空間,咱們能夠使用增量備份。增量備份就是隻備份自上一次備份一來變化的數據。 固然,在還原時確定不想還原自服務器首次啓動以來已經執行全部增量備份。雖然理論上能夠,可是會很是慢,而且須要大量的空間來存放備份,關鍵還容易出錯。所以,常規的完整備份仍然是頗有必要的。 然而,最好混合使用完整備份和邏輯備份以制定優秀的備份策略。好比,咱們能夠每週進行一次完整備份以及天天晚上進行增量備份。若是想在災難發生後還原數據,咱們須要還原最近的完整備份以及其後的全部增量備份。 備份和複製 備份和複製是兩個相關的主題。它們都是經過保存雙份數據來解決災難後的數據恢復問題。 然而!複製不能替代良好的備份策略。事實上,這兩種技術在概念上徹底不一樣。備份是數據的靜態一致快照,它永遠不會改變。複製是slave端重現master端進行的全部操做,所以數據會隨master端改變的。 複製環境中,咱們能夠選擇在哪裏進行備份操做。最好別在master端進行備份,由於master端用來接收客戶端請求,應該儘可能避免拖慢甚至影響master端的正常工做。最好是在slave端進行備份,就是那種複製環境末端的服務器。然而,複製環境中的master端和slave端會有一個延遲,延遲甚至可能達到幾小時或者幾天。雖然這對於複製是能夠接受的。可是備份應該是包含最近的數據。所以,若是對於複製延遲並不敏感的話,能夠在slave端進行備份。複製技術咱們第九章再說。 數據庫集羣是很是複雜,高可用的複製環境。在第十二章MariaDB galera cluster 中。咱們將會討論MariaDB中最經常使用的集羣解決方案。galera會保證數據在全部的節點同步更新。這種狀況下,若是其中的某個節點沒有用來接收客戶端請求,那麼從該節點進行備份是個不錯的選擇。或者,咱們也能夠選擇硬件性能最強勁的那臺服務器。 備份前的準備工做 到此,咱們已經討論了備份的重要以及各類備份的特色。如今咱們將會討論實施這些備份的詳細步驟。可是在討論具體細節以前,先問個重要問題:在咱們選擇了具體的備份策略以後,咱們應該怎麼辦? 對於每一種備份方法,咱們均可以按照如下的步驟進行 1 編寫必要的腳本 備份須要自動化機進行,所以咱們須要編寫cron任務或者是其餘的以使備份按期自動執行的方法。 2測試備份的數據 能夠使用開發環境測試。好比先部署上測試數據,進行一次備份。檢查備份是否順利完成。以及整個備份的時間是否在咱們可接受的範圍以內。 3 測試數據還原 假設截至到如今咱們的數據已經被大量修改過,而後咱們想經過備份進行還原。須要先檢查一切是否都已經就緒(包括準確的備份路徑,數據文件夾,my.cnf參數文件路徑等)。當災難發生後咱們知道準確的信息是很是有用的。這能夠使得咱們的還原過程進行的又對又快。 4 對整個過程編寫文檔 若是咱們沒有記住如何使用,即使是最好的備份還原策略都是無用的,所以把整個過程文檔化是很是有必要的。 5 切換到生產環境 當咱們真的作好準備的時候,這一步就能夠在生產環境上進行了。 本書是關於MariaDB的。並不涉及cron job,shell命令,程序或者是測試方法等內容。在全部的章節中,將僅討論主題的核心內容:如何進行備份和還原。可是當把這些技術應用於真實環境時,最好遵循以前提到的幾個步驟以便保證整個過程都會按照咱們的預期進行發展。 經過mysqldump建立dump文件 mysqldump是用來建立熱邏輯備份最有力的工具。全部的MariaDB的發行版中都包含該工具。能夠在bin文件夾中找到。(最好配上環境變量) 一般,mysqldump用來建立一個dump文件:它會鏈接到MariaDB,讀取須要備份的數據並建立一個包含能夠還原全部數據的sql語句的文件。它由幾個選項可讓咱們過濾不想要的數據。dump文件也能夠進行手工修改以應對真實的需求。因爲生成的是可執行的sql語句,所以能夠在更老版本的MariaDB, MySQL甚至是其餘DBMS中進行還原。 因爲全部這些緣由,mysqldump是一個很是靈活的程序。這就解釋了爲何mysqldump是操做邏輯備份的最佳工做。它能夠應對多種不一樣的需求,好比從一臺服務器複製一個數據庫或者一張表到另外一臺服務器中或者是生成dump文件以讓應用程序安裝過程當中自動執行。 轉儲dump文件的缺點是它們會佔用大量空間。由於這種備份出來的文件數據不只沒有壓縮,並且還多了一大堆insert語句。然而,mysqldump也支持建立文本類型的備份,咱們在下面的章節會進行介紹: 取決因而否備份服務器中的全部數據庫,mysqldump支持三種不一樣的語法。好比備份部分數據庫或者是數據庫中的部分表。命令以下: 以上三種狀況備份出來的dump文件都不會包含use命令。由於用戶極可能想要在別的數據庫中重建備份的數據 當導出多個數據庫時,若是想排除某些表,能夠使用以下命令 --ignore-table-db_name.table_name 若是想排除多個表,則必須屢次編寫該選項。注意不要使用逗號進行隔開,使用空格便可,好比 --ignore-table_db_name.table_one --ignore-table=db_name.table_two ... mysqldump 使用和MySQL命令行客戶端同樣的方式進行鏈接。 默認狀況下,dump文件會包含creata database語句。若是想跳過它,能夠使用--no-create-db 選項。一般咱們會在create database以前有一個drop database的動做。所以,若是數據損壞須要經過正確的數據進行完整替換,能夠使用--add-drop-database選項。默認全部的表定義和數據都會包含在dump文件中,可是若是使用了--no_create_info選項,則不會包含表定義,--no-data選項不會包含表數據。在create table語句中的表選項語句並不是是標準的,而且僅在指定了 --table-option選項時纔會有效(表選項在MariaDB中可能正常執行,可是在MySQL中很差說) 有時候咱們不想經過dump來刪除和替換已有的數據庫,由於該庫可能包含咱們想保留的表。此時,咱們想到了能夠針對表來進行完整替換。此時咱們能夠使用 --add-drop-table選項,它會在每一個create table語句以前添加一個drop table命令。另外一方面,咱們極可能想讓數據經過replace而不是insert進行插入:dump數據將會替換已有數據,可是若是表中包含dump文件中沒有的行,那些行將會被保留。這能夠經過 --replace 選項完成。還能夠使用--insert-ignore,它會把insert轉換成 insert ignore 。這能夠用在導入數據時只插入表中不存在的數據。 //* 注意replace和insert ignore的主要不一樣,replace會刪除已有數據,而insert ignore會忽略已有數據。有個重要的概念叫作 auto_increment。replace會刪除原有數據而後進行插入,雖然數據部分徹底相等,可是自動提交列已經不同了。若是外鍵不用於保留交叉表數據的完整性,則會致使一些問題。若是使用了外鍵,那麼replace 過程會很慢 *// 默認狀況下不包含程序部分,好比觸發器,過程,函數,等。然而,一個完整的邏輯備份應該包含這些內容。而且也用不了多大空間。若是想在dump中包含這些內容,能夠使用 --triggers , --routines 和 --events 選項 一般咱們想在一個事物中完成整個dump過程。這樣能夠保證數據的一致性。若是咱們指定了--single-transaction 選項,mysqldump會在 repeatable read 隔離級別開始事物,並在完成dump過程後發出commit命令。--no-autocommit 選項會使用set autocommit=0 和commit 對轉儲文件中的每一個表進行插入。這樣還原更快,可是當插入其中一張表時,其餘表能夠被其餘會話修改。 當dump一個非事物表時,--single-transaction 選項沒法保證數據一致性。所以,這時候咱們須要使用--lock-all-tables選項來鎖住表。此選項會在全部數據庫上得到一個全局讀鎖。它會阻塞服務器上的全部寫操做直到dump過程完成。這也是惟一一種保證數據庫中非事物表的事物一致性的方法。(拗口,實際上是:只有全局鎖能解決非事物表導出不一致的問題) 然而一般咱們只須要在每一個數據庫的基礎上保證數據完整性,此時能夠使用--lock-tables選項,它一次只鎖住一個數據庫。--add-locks 選項會在每一個表插入以前添加lock tables在插入以後添加unlock tables 命令。--disable-keys 選項會在還原myisam表時使用alter table .... disable keys 來加速還原動做。 //* 記住,lock tables 和 unlock tables 會在當前事物包含中隱式提交, 所以一些所提到的選項是相互排斥的,一塊兒使用--no-autocommit和--add-lock是沒有意義的,由於表鎖會使事務無效。若是咱們想用多行插入來替代單行插入,能夠在lock table的狀況下使用 --extended-insert 選項 *// 默認狀況下,mysqldump從服務器中讀取全部的行到buffer中而後把它們一塊兒寫入到dump文件。這是基於性能優化考慮,當導出大量數據時,它須要大量內存。爲避免緩衝行(bufferizing 不知道怎麼翻譯,難道是相似oracle的直接路徑繞過PGA?),能夠指定--quick 選項。 如下是一個典型的dump文件 當出現下面這些行的時候後,數據開始真正的dump 還原dump文件很是簡單。最簡單的就是打開文件執行語句。有許多種方法能夠完成,好比,若是dump文件很小,能夠複製它的內容而後粘貼到你喜歡的gui工具中。然而最經常使用的方法仍是讓MySQL命令行來調用dump文件做爲輸入。如下語法能夠在全平臺使用,包括windows 若是如今已經處在MySQL命令行中,那麼能夠使用source命令來指定要導入的文件 文本格式的備份 備份一張表能夠是一種特定的文本格式:以特定格式分割開全部列的人類可讀的文本格式(耐心斷句)。好比最多見的以逗號分割的CSV格式。MariaDB支持如下幾種方式來建立文本格式的文件 1 mysqldump 使用--tab 選項 2 select ... into outfile 命令 3 CSV 存儲引擎 4 CONNECT 存儲引擎 至於還原文本格式的備份,能夠經過以下幾種方式 1 mysqlinport命令 2 load data infile 命令 3 CSV存儲引擎 4 connect 存儲引擎 mysqldump中的--tab選項 經過mysqldump命令,使用--tab選項,能夠爲每一個dump的表生成兩個文件。這兩個文件的名字和原來的表名同樣,不一樣之處在擴展名。其中一個以.sql結尾,其包含了建立一張空表所必要的create table命令。固然這個文件須要最早被執行除非目的端表已經存在。另外一個是.txt文件。其包含了文本格式的備份。默認狀況下是以製表符來分割每一個值。而且使用換行符來分隔行。分隔符能夠經過mysqldump的不一樣選項來按需指定。這些選項咱們之後再說,由於它們須要使用不少工具和命令。 --tab 指定了 .sql 和 .txt 文件的路徑。好比 --tab=/tmp/backup 經過 mysqlimport 導入dump文件 mysqlimport 是mysqldump的另外一個延伸工具,它用來導入文本格式的備份。和mysqldump同樣,全部的MariaDB發行版都內置該工具而且能夠在bin目錄中找到。語法以下: 由於mysqlimport須要知道表應該被還原到哪裏,所以數據庫的名字必須指定。而後,至少指定一個須要導入的文件。文件名即表名。擴展名到無所謂,能夠是.csv .txt 或者是其餘任何都行。這會有一個有趣的後果:兩個文件名同樣可是擴展名不一樣的文件會被認爲是同一張表(??哪兒有趣)。好比對於大表,方便起見可能會把一個文件分割成多個。mysqlimport 命令有不少選項能夠指定使用什麼字符來分割行和列。這些選項咱們在後面會說。 默認狀況下,須要導入的文本文件多半位於服務器中。若是經過遠程執行mysqlimport。導入的文件也能夠在客戶端,可是須要指定--local 選項。 若是須要的話,能夠使用 --ignore-lines選項來跳過源文件的第一行,好比 --ignore-lines=1.當第一行是字段名,或者是一些相關注釋(好比說時間戳或者軟件產品信息等)的時候,這個選項很是有用。 另外一個重要的選項是 --delete,使用該參數會在導入以前清空目標表。 當導入的目標端中已經存在文件中的記錄時,能夠使用--replace 選項來替換該記錄,想要達到一樣目的的,也能夠使用 --ignore 選項來直接忽略已經存在的記錄,能夠防止報出一些錯誤(這點和上面的table-option相似)。 當導入大量數據時,也能夠使用並行方式導入。 --use-threads 選項來指定多個線程來導入數據。好比若是咱們使用 --use-threads=2選項,mysqldump則會使用兩個線程。 經過select ... into outfile 來建立文本分割的文件 帶有 into outfile子句的select 命令,能夠把檢索的結果集寫入到文件。默認的,文件會存儲到MariaDB的安裝目錄中(並非數據文件夾)。固然也能夠指定具體的導出路徑。記住,MariaDB的用戶必須對指定的路徑具備文件級別的讀寫權限。在Linux系統中,/tmp目錄是個不錯的選擇。注意,若是目標路徑文件已經存在,會報錯。由於此種方式只能把記錄導出到本地服務器,所以使用客戶端或者是遠程都是不行的。 結果集不會輸出到標準輸出(客戶端),可是會收到統計的記錄數(或者是錯誤) 例子以下: 默認的,製表符用來分割字段,換行符來分隔行。(後面是幾句廢話,意思就是能夠經過選項來改變分隔符) select ... into outfile 命令是在兩個服務器或者是MariaDB和其餘軟件之間交換數據最有力的工具。使用它來建立備份反而不多用。可是當咱們僅備份表的一部分,好比使用join或者where子句的時候。就很是有用。 運行 select ... into dumpfile 命令等價於如下用法: MySQL -e "select ..." > file_name 考慮下面這個例子: MySQL -e "select * from information_schema.tables order by table_schema,table_name" > /tmp/tables.txt 當咱們想要在shell中把查詢結果轉儲到文件時,此語法很是有用。並且,它不只能夠在服務器端使用,客戶端一樣也能夠。 經過Show create table 命令導出表定義 有時咱們想得到表的建立語句。使用 show create table 命令是很是有效的,不信你看: 固然也能夠對數據庫使用相似的命令,好比: 使用以上兩個命令。在數據庫發生意外時,咱們就能夠經過 select ... into outfile 來還原數據。不過大多數狀況下,它們仍是多用在交換數據上面。 show create table 和 show create database 不支持把結果轉儲到文件。然而能夠經過編寫腳原本實現。 經過load data infile來加載dump文件 load data infile 算是select ... into outfile的反向工具,用來把導出的文件導入到已經存在的一張表中。 語法以下: 在語法描述中,設定分隔符的選項都在 other_options 中。巴拉巴拉巴拉。。一堆廢話。隨後再說。 low_priority 和 concurrent 僅用在非事物表中。low_priority 選項會比讀操做的優先級更低。concurrent 選項容許myisam在當前進行插入操做。這兩個選項都會減慢load的速度,可是不會阻塞當前的鏈接:若是指定了low_priority,其餘會話中的查詢能夠被順利執行。若是使用了concruuent,那麼當前的插入操做也能夠成功。 若是導入的文件須要由客戶端發送到服務器端,那麼必須指定local選項。不然假定文件在服務器本地。此時,MariaDB須要有文件相關的權限。另外不一樣之處是,當使用local選項時,若是出現主鍵衝突的錯誤,會把 error轉變成warning而且不會中斷整個導入過程。 replace 和ignore能夠解決重複值的問題。replace會替換掉原有行。ignore不會動已有行,而且也不會拋出主鍵重複的錯誤。 INTO TABLE選項指定了目標表,能夠是一個或多個目標分區。 //* character set 選項應該永遠都使用,它表示文件使用的字符集。默認值是從character_set_database 變量中讀取到的 *// 能夠經過指定IGNORE n LINES 關鍵字來跳過文件的頭幾行。若是文件頭頭幾行不是主要內容,好比說是列名的話。此參數頗有用。 除非經過alter table 對錶進行過更改,不然服務器會假定你須要導出的列的順序是按照 create table 語句走的。除了經過create table 查看列順序,經過 DESC命令也能夠。 能夠在括號之間明確指定順序,方式與在INSERT語句中指定的相同 同時支持使用SET子句對多列進行計算。好比,若是 product表有一個price列;它還有一個sales_tax列,其值對應爲price的10%. 因爲MariaDB支持VIRTUAL和PERSISTENT計算列,一般無需使用load data infile 來插入已經計算好的值。可是在極個別的狀況下也可能須要這麼幹。好比數據庫是在多年前設計的,當時尚未這樣的特性,而且咱們也不想對它進行修改。 這多是爲了MySQL兼容性,或者由於計算值的表達式是不肯定的,因爲數據庫不能用於VIRTUAL列。此時能夠使用 SET語句來在導入以前先進行計算: SET SALES_TAX =PRICE / 100*20 (是的你沒看錯,上面寫的仍是10%,下面他寫成了20) 分隔符選項和子句 不管是mysqldump,mysqlimport 這樣的命令行工具,仍是select 。。into outfile 和 load data infile 這樣的sql語句,他們都支持一些選項來指定字符,好比:分割值, 轉義,換行等。 這些選項都同樣。可是對於sql語句略有不一樣。 如下的表展現了具體的語法以及含義(此處不翻,忽然變懶了。) 在SQL語句中,當使用多個字段或行子句時,不得重複使用 FIELDS和LINES。好比,正確地語法應該是 FIFLD TERMINATED BY ',' ESCAPED BY ‘|’ 。全部的sql子句都是可選的;若是它們出現,就必須以與上表中使用的相同的順序出現。此處 COLUMNS和FIELDS同義。 建立和還原dump文件示例 頗有必要講講如何建立和恢復dump文件。如今來看個簡單的例子。展現一下如何使用select into outfile 來建立一個邏輯備份以及如何使用 load data infile 來進行還原。 先建立一張表來展現例子: 數據準備好了,如今使用mysqldump來導出數據,而後檢查一下第一行是否正確。這張表很是小,所以也不必僅檢查第一行了。然而在真實狀況下,最好仍是檢查一下。本例中,咱們仍然會進行檢查操做: 看上去還不錯。如今再使用select .. into outfile 來對該表進行備份。此語句與以前的效果相同,區別就在於不會生成表定義文件。例子以下: 而後使用md5sum工具來檢查一下導出的內容是否相等 因爲md5值相等,所以能夠判斷兩個文件也是相等的。 在還原操做執行以前,先清空表 如今先經過mysqlimport 進行還原: 隨後再使用與之等效的 load data infile 語句。在進行下面的步驟以前一樣須要先清空表。 經過CONNECT 和CSV引擎進行備份 使用CSV引擎建立的表爲使用逗號分的隔數據文件,可用於備份或數據交換。CONNECT引擎就更加複雜了:它支持多種表類型。每種表類型都有不一樣的數據格式,支持的格式包括CSV,XML,HTML 和由dBase建立的數據文件。CONNECT引擎甚至能夠經過ODBC鏈接到遠程服務器來對遠程節點進行讀寫操做。 經過CSV或者CONNECT來建立備份很是容易。例子以下: 可是沒啥用。若是該表包含null值,CSV引擎就不能使用。這是很是重要的一個限制,但不只僅於此。所以更傾向於使用CONNECT。使用CSV的惟一緣由就是在mariadb10以前的版本不支持connect。也不能後期添加。 默認connect沒有安裝,所以須要經過如下命令進行安裝。 如今咱們能夠使用它來進行備份了。把connect引擎的表類型指定爲CSV,由於這種類型用來還原數據很是有效。固然也能夠使用別的類型,但此處我就這麼用還能咋地?注意下面例子中的表選項: 這個例子中,咱們使用了CSV相關的全部選項。 1 table_type: 以前所說,設定源數據表的類型(此例中爲CSV) 2 file_name : 表示數據文件的名稱和可選的路徑 3 HUGE: 這默認值爲0.若是表大於2 GB,經過將CONNECT設置爲1來通知CONNECT是有意義的。 4 COMPRESS : 因爲這是備份,所以最好壓縮一下, 與InnoDB同樣,CONNECT使用zlib庫和LZ77算法。 5 READONLY: 因爲這是備份,因此使表只讀是更安全的。 6 DATA_CHARSET : 使用的字符集。 7 SEP_CHAR: 列分隔符。 8 ENDING : 字符結尾的長度。 Unix系統爲1(行以\ n結尾),Windows上爲2(行以\ n \ r結尾)。 9 QUOTED : 由於指定了QCHAR,因此能夠省略 10 QCHAR : 引用字符。 11 HEADER : 導出文件第一行是不是列名 (以上這幾個含義翻譯的實在牽強。查詢翻譯軟件也沒法得到更理想的解釋。各位本身上手試試吧,母猴依稀) 還原一樣很是簡單:咱們只須要刪除/tmp 中的數據文件而且經過備份替換便可。經過CONNECT引擎,咱們無需作更多的工做便可使用備份。而後,咱們能夠使用正常的INSERT ... SELECT或CREATE TABLE ... SELECT語句將備分內容複製到原始表中。 物理備份 物理備份是複製MariaDB的數據庫定義,數據和索引文件,配置文件和日誌。因爲數據是以一種很是緊湊的方式存儲的,物理備份一般是最方便的一種備份方式。同時也僅有物理備份能夠備份配置文件和日誌。 然而當進行物理備份時,必須對服務器進行加鎖,也就是說在一段時間內服務器會進入不可用的狀態。或者乾脆停機進行備份。 何種文件須要進行備份 完整的備份應該包含如下幾種文件:表文件,觸發器文件,日誌和配置文件。 表文件 表文件存放在data文件夾中。使用的存儲引擎決定了數據和索引的文件類型。data文件夾中會爲每一個數據庫建立一個目錄。名字和數據庫名字相同。因此最好別給數據庫起什麼奇奇怪怪的名字。表文件存放在對應的數據庫文件下。文件名爲表名。一樣最好別起什麼奇奇怪怪的名字。可是表文件的擴展名要看具體的文件類型。 若是是分區表,由於關聯了多個數據和索引文件,這些文件的命名格式大體是這樣的: .par文件用來存儲分區的元數據。 data 文件夾的路徑經過@@datadir變量進行設定。 對於innodb 的系統表空間,能夠經過@@innodb_data_home_dir變量進行設定。其餘表空間能夠經過@@innodb_data_file_path進行單獨指定。值能夠配製成 @@innodb_data_home_dir的相對路徑。 有些存儲引擎,包括最近版本的innodb,支持爲每張表指定不一樣的路徑。路徑能夠經過DATA_DIRECTORY 和INDEX_DIRECTORY表選項指定。此選項能夠經過show create table 命令進行查看。 掌握了以上知識,咱們就能夠對錶或者分區進行選擇性的備份了。 服務器建立的 .frm 文件包含了表的定義。一些存儲引擎在某些狀況下無需這些表定義文件仍舊能夠工做。可是不管使用何種引擎,最好保證該文件存在。 innodb有一個file-per-table 模式會影響到表的建立行爲。具體內容咱們在第七章已經介紹過了。系統表空間老是存在,且以ibdata命名。當一個表經過 file-per-table 模式建立時,對於每張新表,都會有一個與之對應的包含了數據和索引的.ibd文件生成。當關閉file-per-table模式時,新的表將會被建立到系統表空間中。 許多存儲引擎爲索引和數據使用了不一樣的文件格式,下面是一些常見的擴展名: MERGE存儲引擎不會建立數據和索引文件,可是它會使用一種MRG的文件,它是一張包含了與myisam表有關的清單。Aria也會使用日誌,它們的名字是aria_log , 而且擴展名是漸進的數字,aria_log_control 文件也是必要的。archive引擎的索引支持很是有限,CSV乾脆就根本不支持索引。所以這些存儲引擎不使用索引文件。對於CONNECT引擎。SEP_INDEX表選項容許咱們存儲每張表的索引。具體的名字遵循 tablename_indexname.dnx的規則。 主鍵的索引名稱爲PRIMARY。 好比一張myisam1的myisam表使用了三個叫作 p0,p1,p2的分區。相關文件以下: 存儲過程,觸發器和事件,統稱爲存儲程序。 它們旨在使用簡單的SQL腳本實現數據庫的邏輯。這些對象不多變更。然而備份這些程序對於還原來講仍然很是必要。它們的定義存放在系統表空間中,系統表空間包含在MySQL 數據庫中。備份了MySQL庫,就表明備份了全部已有的存儲程序。 然而對於每一個觸發器,均可以在data目錄中找到這樣的文件 trigger_name.TRG trigger_name.TRN 備份觸發器的時候,必定別忘了這些文件。 日誌文件 服務器日誌的路徑和文件名經過一些變量進行設定。這些已經在第二章和第三章講解過了。此處彙總展現一下。 把日誌文件放到data目錄中會使得備份過程變動容易(事實經驗告訴你,最好別這麼幹。備份都是自動的) 配置文件 (前面說了一大串if)簡單來講,若是你一臺機器上只跑一個MariaDB實例。那麼對應的配置文件存放在MariaDB的安裝目錄中,Linux中叫作my.cnf windows下叫作 my.ini Linux系統中,配置文件能夠放在如下任一地方(過短了我就不翻譯了): windows中,路徑能夠是: 熱物理備份 當服務器停機時,複製文件很是容易。可是當服務器運行時就有一個問題:必須確保在備份完成以前沒有對文件進行過修改。 所以須要刷寫最新的變動到磁盤中,而後鎖住表。能夠經過 FLUSH TABLE ... FOR EXPORT 或者是 FLUSH TABLES .. WITH READ LOCK 來完成。 語法以下: 使用 FOR EXPORT 時,table_list 爲必填。with read lock 沒這個要求。可是省略的話,flush tables with read lock 會鎖住全部表。這稱做全局鎖。一個共享表鎖會被加到已命名的表上。 //* 使用以上任一語句鎖定的每一個表都會從query cahce 中刪除。由於服務器知道這些數據將會被替換,之後確定是要從文件中讀新的數據了。 *// 最方便的步驟以下: 1 打開MySQL客戶端 2 執行 flush tables for export 後者flush tables with read lock 並讓客戶端處於打開狀態。 3 複製相關數據文件。 4 客戶端中經過 unlock tables 釋放鎖。 flush tables for export 會鎖住表而且要求存儲引擎刷寫最近的變動到磁盤中。這是備份運行狀態的innodb表的惟一安全方法。然而在MariaDB 10.0以後的版本,for export 子句就不可用了。一樣其餘存儲引擎也再也不支持了。 對於flush tables with read ,刷寫操做由服務器完成,這就意味着即使存儲引擎不支持這麼寫,可是經過服務器來完成也是OK的。然而如以前所說,這個方法對於備份運行狀態的innodb表不大安全。 對於大多數存儲引擎來講, 這兩句並無什麼明顯區別。可是若是備份innodb表,for export 就方便多了。 文件系統快照 一些文件系統或者卷管理器支持快照功能。好比 veritas這種的。其餘文件系統,像XFS能夠經過相似LVM的卷管理器來建立快照。快照是一種建立物理備份很是快速的方法。 無需停機便可建立快照。可是flush tables with read lock 來鎖住表仍是必要的。步驟以下: 1 打開客戶端 2 執行 flush tables with read lock 保持客戶端開啓 3 進入系統控制動態,執行相似下面的命令 mount vxfs snapshot 4 回到客戶端執行 unlock tables 釋放鎖。 大多數Linux發行版中都包含mylvmbackup 工具,能夠自動完成上述過程。 經過rsync完成增量物理備份 rsync是一個Linux中用來增量複製文件的命令。當它對一個以前從未複製過的文件進行復制時,就直接複製它。可是當第二次複製該文件時,它會檢查該文件自上一次複製之後是否被修改過。若是修改過,rsync會值複製修改過的部分,該方式經過網絡進行復制很是迅速。當進行目錄複製時,rsync會檢查目錄中的每一個文件。若是源端目錄被刪除,那麼rsync也會刪除目標端的目錄。然而對於備份來講最好別這樣,若是文件丟失,咱們還期望着備份來進行還原呢。 rsync命令對OLTP數據庫沒啥大用。然而對於OLAP這種包含海量數據而又不多變更的庫很是合適。當備份這些數據庫時。爲節省時間考慮,只想備份已經被修改過的表。若是隨後須要還原,使用對應表的最近備份便可。 如下是一個典型的rsync命令使用方法: 輸出至關長,值截取了一部分。 能夠使用如下選項 1 --progress :展現執行過程信息。輸出很是長,可是出錯的時候能夠找到具體緣由 2 --stats 打印傳輸文件的最終狀態 3 --compress : 經過zlib進行壓縮複製。想法不錯,由於rsync一般用來複制大文件。可是應該讓鎖表時間儘可能短。所以最好在釋放鎖之後再進行壓縮,好比經過gzip或者其餘工具。 4 -r 遞歸複製 5 -t 傳輸文件最近的變動信息。以方便下次增量備份使用。 6 -l 此選項遵循符號連接(若是有)。 咱們一般不但願rsync刪除目錄中已經從源目錄中刪除的文件。 所以,咱們沒有使用--delete選項。 在服務器運行時進行文件複製 若是想還原備份,大多數存儲引擎僅須要在複製備份文件到data目錄以前經過 flush tables with read lock 鎖住表便可。可是這在mariadb10之間的innodb表是不可行的。自mariadb10以來,innodb支持一種叫作 表空間傳輸(transportable tablespaces)的技術。意味着能夠是使用一種特殊的sql語句來複制正在運行的服務器或者爲正在運行的服務器還原相關文件。簡單來講吧,這項技術能夠在服務器運行時執行備份和還原操做。 此技術有些重要的限制 1 innodb 的file-per-table 必須開啓。系統表空間不支持傳輸 2 若是foreign_key_check=ON,則不可複製。不過能夠在複製以前設置改變量爲OFF以關閉外鍵。若是文件隨後被還原了,外鍵約束不會在還原過程當中自動開啓。 3 不一樣版本的MariaDB之間不可用。 只要服務器版本穩定,次要版本升級不該使備份表空間無效。 4 當在兩個服務器之間複製時,目標端必須存在對應表。 爲建立表空間的備份,須要執行如下幾步 1 運行flush tables table_list for export ;爲加上共享鎖 2 爲每一個innodb表建立.cfg文件。以前咱們沒說。此文件僅爲innodb表建立,而且也僅在當把表複製到運行狀態的服務器時有用。 3 表如今處於一致和被鎖的狀態。設置 foreign_key_checks=OFF 4 複製 .ibd和.cfg 文件到備份目錄中 5 設置 foreign_key_checks=ON 6 運行 unlock tables 釋放鎖 在運行時的服務器上還原備份: 1 運行 alter table table_name discard tablespace;爲表加一個排他鎖 2 複製 .ibd和.cfg 文件到data目錄中 3 運行 alter atable table_name import tablespace; 使用 binary log 實施增量備份 binary log 是一系列記錄數據變動狀況的文件。它能夠用做增量備份和複製。 binary log 的目的是可以將變動再次應用於數據庫。對於複製環境,binary log有着更直觀的表現:binary log 經過master 服務器發送到slave中,所以slave能夠應用一樣的變動以保持和master端的數據一致(並不是當即生效)。若是不開啓binary log的話,複製無效。 對於備份來講,binary log文件能夠用來實施增量備份。當災難發生後,數據能夠經過最近的完整備份進行還原。能夠是物理備份或者邏輯備份。由於數據有些過期,此時能夠使用binary log。即等效最近的增量備份。由於其包含了全部的數據庫變動操做。所以能夠應用於完整備份。 可能舉個例子會更清晰點。假若有個線上商店使用的MariaDB。天天數據都會改變:新的產品賣出買進啊,新的用戶註冊啊,網站流量數據統計啊等等。 咱們顯然須要常常備份數據。可是因爲數據量很大而且網站流量很是高,所以不想減慢網站速度和使用大量磁盤空間來保存備份。這時能夠每週選擇一天網站流量低的時候進行一次完整備份。可是若是完整備份是在週日進行,然而週六晚上出事了,咱們又不想丟失上一週的任何數據。能夠在天天流量低的時候進行增量備份。最方便的方法就是循環使用binary log。循環日誌也就是說新的日誌被建立,當前使用的日誌文件得以保留,或留在當前目錄,或另行歸檔。爲安全考慮,能夠把這些文件備份放到遠程存儲服務器上。舊的日誌留在原來的目錄中對於還原操做很是有用。可是若是磁盤出問題呢?日誌文件應該被存放在不止一塊磁盤中。當新的完整備份建立後,這些保留整週的日誌文件就能夠放心地刪除了。不然磁盤不夠用咋辦。(日誌保留策略取決於公司的業務要求。極少狀況下可能要求回檔到很早之前。好比說消除證據。) binary log能夠以如下三種格式存儲(我重複一下斷句「能夠,以,如下」) 基於語句 statement_based 基於行row-based 混合 mixed 對於statement-based 格式的日誌來講。僅記錄sql語句。這種格式有些限制:有些sql語句或者函數就不能用了,由於他們的執行結果可能每次都不同。好比 NOW() 函數的結果取決於當前的時間。對於row-based 格式的日誌來講,它會記錄數據的變動值。mixed 日誌有時安全,也有不安全的可能。選擇一種可靠的格式對於複製影響很是重大。具體咱們在第九章時候再說。 binary log也會在第九章中詳細講解。本章僅介紹一些binary log的重要概念。 能夠經過 --log-bin啓動選項或者 配置文件中的 log-bin 參數來開啓binary log。不管選擇哪一種方式,其值都是具體的文件名,而並不是 ON OFF這種。默認的名字是服務器的主機名後跟隨-bin 字符。日誌文件一樣也會添加數字到擴展名中進行編號。 //* 若是開啓binary log,@@log_bin變量爲ON。@@log_bin_basename變量爲當前日誌文件的basename。 * // show master status 命令能夠展現當前日誌文件的完整名稱。若是沒有使用複製環境,輸出結果大體是這樣的: show binary logs 命令能夠展現當前的和舊的binary 日誌文件 binary log 是以一種格式緊湊而且人和MariaDB都不可直接閱讀的文件。若是想使用或者應用該文件,能夠經過mysqlbinlog完成。此工具隨MariaDB安裝文件一塊兒發佈,它能夠用來把日誌文件轉換成可讀的sql語句。 mysqlbinlog能夠用來把日誌解析出來的sql語句發送到MySQL客戶端。執行方法以下: 固然能夠一次轉換多個文件,跟上例同樣,可是順序必須正確。最好不要經過屢次調用該命令來發送文件。 這是由於文件可能會嘗試使用在另外一個文件中建立的臨時表。 若是咱們單獨的調用,臨時表將在文件執行結束時丟失,而且不能用於下一個文件。 有時由於手殘執行了諸如 delete,drop table或者drop database 之類的命令致使數據損毀。此時,咱們想經過還原最近的完整備份和應用相關的binary log 來完成恢復。可是一樣想避免二次執行相同語句而致使數據被毀。爲此,能夠把mysqlbinlog的輸出寫到文件中。手動編輯文件而後發送到數據庫服務器,好比這樣: 固然能夠根據時間點來選擇相應的事物。不管是開始仍是結束時間均可以。好比這樣: 此項技術能夠避免執行了錯誤的語句致使重要數據被刪除。能夠經過檢查mysqlbinlog的輸出來確認須要執行的時間範圍是否如咱們所指望的那樣。 對大多數狀況來講,時間點並不是是個精確值。由於時間戳沒有精確到微妙這種級別,而且同一時間可能會發生不少數據變動。一般無需執行全部。幸運的是,每一個條目在binary log中都有惟一的position值。爲校驗mysqlbinlog的輸出,能夠找出咱們想開始執行的位置點。 它們做爲註釋和其餘信息寫在一塊兒: 本例中,insert 的位置是694 除了指定 --start-datetime 和--stop-datetime 以外,還能夠指定具體的位置點來進行更精確的篩選,好比這樣: (--start-position 和 --stop-position) percona xtraBackup percona xtrabackup 是一款來自 percona的物理備份工具。其最重要的特性就是能夠在服務器運行時對innodb表進行無鎖備份。至於使用其餘存儲引擎的表只須要在複製結束時鎖那麼一下下。percona xtrabackup支持增量備份。軟件能夠從 percona 的官網進行下載。 percona xtrabackup 由幾個組件構成。核心組件就是 xtrabacup程序。 它內嵌了用於訪問InnoDB表空間的InnoDB程序。除了備份innodb外也支持其餘引擎。能夠備份表定文件,觸發器,以及經過調用 xtrabackup 來備份.ibd。percona xtrabackup 是一款複雜的工具。xbcrypt是一個獨立的命令,用來對備份文件進行加解密。本書中,咱們僅涉及如何使用 innobackupex來建立還原完整和增量備份。關於xtrabckup的更加詳細地信息,你們能夠從官網上閱讀。此處提供相關地址: http://www.percona.com/doc/percona-xtrabackup/ 操做備份 percona xtrabackup 能夠實現完整和部分備份。部分備份無需複製全部數據庫的全部表。在第一次完整備份或者部分備份以後。percona xtrabackup就能夠實現增量備份了。本章講解如何實現全部的備份類型。 完整備份 完整備份無需多餘的選項,下面的命令就能夠簡單地實現完整備份。 innobackupoex --user=root --password=root /tmp/backup 固然--user 和 --password 選項必須指定,其爲mysql.user 中的用戶密碼。最後的路徑表示備份將要存放的地方。 默認狀況下,會在backup目錄下建立一個子目錄,其包含了當前的備份。目錄的名字爲當前的時間,格式大概是這樣: 2014-4-10_16-30-18. 這一般是一種很是實用的歸檔備份方法。若是不想自動生成日期名字的話,只須要指明 --no-timestamp 選項便可。 部分備份 默認是完整備份。意思是它會包含全部數據庫的全部表。固然也能夠指定哪一個庫的哪一個表必須進行備份。 --databases 選項用來指定須要備份的數據庫,也能夠指定表。多個值用空格隔開。每一個參數能夠是數據庫或者表名。當只指定一個數據庫時,該庫下全部的表都會被備份。好比,若是想包含db_1的全部表和db_2的user表。大體語法以下: 若是須要指定的數據庫和表太多的話,也能夠寫到文件中。innobackupex一樣支持從文件中讀取列表。每一個表或庫爲一行。不過要使用 --tables-file 參數: --include 參數容許使用正則表達式來匹配表或庫。好比這樣: 準備備份 percona xtrabackup 每次拷貝InnoDB文件都無需加鎖。也就是說。當表被複制時,用戶能夠修改表。但結果是複製的表極可能是不一致的。嘗試還原一個不一致的表會損毀服務器。爲保證備份一致性。須要執行prepared操做。prepare操做的在複製完成以後進行,而且無需鏈接到服務器和訪問服務器中的任何文件。惟一的限制就是完成準備操做的xtrabackupex版本必須和複製操做的xtrabackupex版本同樣。 innodb有一些用來重現或回檔事物的日誌。percona xtrabackup 會把這樣的日誌一塊兒備份進來。在prepare的過程當中,xtrabackup程序會對備份進行重作和回滾操做。由於程序內嵌了修改過的innodb程序,因此安全性是沒問題的。在準備過程結束以後。全部的.ibd文件和日誌都處於一致狀態。此時若是有必要的話就能夠直接導入到data目錄中了。 準備完整備份 爲prepare備份,咱們須要應用全部的innodb日誌。事實上,僅須要再次調用 innobackupex 且帶有 --apply-logs選項便可: (不知道他爲什麼舉這個例子。innobackupex在哪?) 準備過程可能會受大的innodb表影響致使速度很慢。percona xtrabackup支持內存使用量參數來加速準備過程。默認的使用的內存爲100MB,顯然過小了。若是想加速這個過程。能夠使用--use-memory 參數。好比: --use-memory=2G 若是prepare過程成功了。innobackupex 會在最後一行打印信息告訴咱們最新的日誌序列號。若是咱們想要執行增量備份而且讓 percona xtrabackup 沒法訪問到這部分備份,就須要把該序列號保存在別的地方。這種狀況是有可能的。好比把備份複製到遠程服務器而後從本地刪除相應文件。 準備部分備份 Prepare一個部分備份的語法有些不一樣,看例子: 對於不包括在備份中的每一個表,可能會出現一條警告,通知咱們該表缺失。發生這種狀況是由於 .frm 文件包含了這些表的定義。能夠直接忽略。 對於包含的表, 會在backup 目錄中建立 .exp 文件。該文件用來還原部分備份。 還原備份 若是想還原備份,能夠直接把須要的文件複製到data目錄中便可。然而 xtrabackupex提供了更簡單的方法。 恢復完整備份 percona xtrabackup 不能在服務器運行時進行恢復操做。若是想恢復完整備份,須要先停掉服務器。而後調用 innobackupex --copy-back 命令並指定 backup目錄。innobackupex會從配置文件中讀取 data目錄的地址。命令以下: 還原部分備份 能夠恢復單獨的表,正在運行的服務器也能夠。使用方法本章已經講解過了。(就這麼短,真的) 備份的安全性 若是數據庫包含敏感數據,說明備份一樣包含敏感內容。這點千萬別忘了。此處有幾點來保證備份安全的經驗。 1 設置正確地權限:只有許可的用戶才能對備份文件進行讀寫 2 以安全方式傳輸備份。若是備份須要傳送的遠程服務器,傳輸必須是以安全的方式進行。好比經過SCP命令來使用SSH隧道進行復制。 3 加密備份:畢竟備份被偷走仍是有可能的 4 備份存放到物理上安全的地方:物理安全指的是沒有受權的人不能進去, 應配備防盜和防火裝置。 若是有必要的話,能夠使用防火牆或者selinux(我的認爲防火牆應該由硬件來完成,使用IPS或者IDS。保證進入的內網的數據是乾淨的。重複使用防火牆沒啥太大意義,還拖慢性能) 修復表 當一張表損壞後,有時無需使用備份來進行替換。它雖然也算個解決辦法,可是說究竟是會丟失一部分數據,除非表自從上次備份以來就沒動過。所以最好先試試修復表。 修復步驟取決於使用何種存儲引擎。 innodb 會在服務器啓動時調用恢復進程自動完成。可是必須經過DBA來進行配置。 Myisam和Aria也能夠在啓動時自動恢復。除此以外也支持經過REPAIR TABLE的語句或者是當服務器停機時經過MariaDB中特定的工具。 其餘存儲引擎一樣支持 REPAIR TABLE //* 有些修復技術在安全性上考慮欠妥,但即使是最安全的方法,也有可能致使恢復失敗甚至是數據錯誤。雖然這種可能性很小,可是仍是有的。所以建議在修復表以前先對錶進行一次物理備份。 *// 還原innodb 表 一般 innodb表無需修復。即使當表損壞,select ... into oufile 也可建立正確地數據。以前所說,此方法能夠建立備份並用以還原。然而若是發生某種類型的損壞,select 會致使innodb崩潰。此時就不得不修復損壞的表或者直接經過備份還原了。 檢查表 innodb 支持 check table 命令。若是表發生故障, 一般,該語句會返回一個結果集,其最後一行 Msg_type值爲error,Msg_text列值爲Corrupt。 在這種狀況下,損壞的表或索引被標記爲已損壞,而且直到問題解決以前都不能再使用。若是經過check table 檢查出一些錯誤。 innodb 可能會當即中止服務器以阻止問題擴散。check table 在本章最後部分講解。 事物日誌 innodb 爲實現事物使用了兩種日誌: redo 和 undo 。分別用來重現事物和取消未提交的事物。在崩潰恢復中都會用到。 在修改表數據以前,innodb須要把更改的內容寫到redo 日誌中。若是數據庫在修改完畢以前崩潰。innodb仍然能夠在重啓階段使用redo 日誌中的信息重作整個事物。 redo 日誌存儲成單獨地物理文件。爲redo 文件提供了一個安全的buffer來減小對該文件的寫操做。undo物理存放在系統表空間中,固然也能夠配置爲其餘的表空間。若是磁盤是性能瓶頸,則配置這些物理存儲的日誌對性能優化很是重要。配置事物日誌咱們11章時候再說。 強制數據恢復 即便檢測到數據損壞,innodb默認也不會執行數據恢復。只有在@@innodb_force_recovery設置爲比0大的時候innodb 纔會開始恢復進程。此變量非動態,所以必須在配置文件中對 innodb_force_recovery 參數進行設置。 只能使用大於0的值來恢復數據。恢復成功後,必須把這個值設置回0並重啓。(有點設置成0就進入特殊的啓動模式的感受) @@innodb_force_recovery命令決定了innodb採起何種行爲來執行恢復操做。值越大功能越多,程 包含關係。值越小越安全。所以最好先嚐試比較小的值。若是不行的話再嘗試更高的。1-3基本安全。4能夠致使二級索引失效。若是數據安全,二級索引還能夠重建。5可能形成數據不一致。 6會致使頁面處於過期狀態。可能會致使這種錯誤被傳播到別的地方。若是沒有必要,最好別用。 當值大於3時,innodb拒絕全部的嘗試修改數據的DML操做。當值爲6時,innodb拒絕 CREATE TABLE和 DROP TABLE操做. 下面是對應值的詳細解釋 0 正常執行(不恢復) 1 嘗試跳過沖突頁,select語句不會致使innodb崩潰,衝突數據不會返回。 2 不啓動master 和 purge線程 3 跳過回滾的事物 4 change buffer 不會合並頁面。innodb表的數據不會進行統計 5 忽略undo日誌。 對執行了一半的事務的不作回滾操做。 6 忽略redo日誌。從mariadb10.0起,直到服務器重啓,innodb一直處於只讀狀態。 當設置爲6時,select中的where或者order by子句都會失敗。簡單的全量查詢能夠幫助咱們建立一張備份表。然而當發生內部頁錯誤時可能會出錯。若是查詢在某一點失敗。仍能夠嘗試使用where 或者order 來跳過錯誤頁。 修復非innodb表 修復表的過程取決於存儲引擎 。不過大多數的存儲引擎都支持經過sql語句來檢查文件完整性和執行修復操做。myisam和aria支持其餘的恢復方法。sql語句容許咱們能夠經過如下兩種方式處理數據錯誤 1 check table語句來檢查表是否出錯 2 repair table 語句來修復出錯的數據 myisam 和aria一樣支持 1 啓動時的自動回覆 2 myisamchk和aria_chk 工具來修復對應引擎的表 check table 語句 當運行sql語句時,可能會收到一個當前咱們正使用的表被損壞的信息。好比這樣 在其餘狀況下,MariaDB不會意識到表已損壞, 咱們可能會意識到是由於咱們收到不完整的結果集。最壞的狀況就是服務器崩潰。若是咱們按期檢查錯誤日。就會注意到這點。 在崩潰以前,可能會看到InnoDB錯誤,通知咱們表已損壞。 若是咱們認爲表出錯,可是又不太確定。那麼check table可讓咱們無需中止服務器來檢查表的完整性。如下幾種引擎都支持check table語句: innodb,myisam,aria,archive,csv。 檢查的語法以下: 當檢查分區表時,下面的語句可讓咱們僅檢查一個分區: Table_name 和partition_list若有多個用逗號隔開。能夠指定0或多個選項。選項參數及釋義以下: 1 for upgrade:當須要導入的表文件是經過更老版本的MariaDB建立的時很是有用。在把數據導入新版本的mairadb服務器時,應該調用mysql_upgrade腳本對文件進行預處理。固然此選項也能夠用來升級表文件。 2 changed: 只檢查自上次CHECK TABLE命令以來修改過的表。最近一次更新和檢查時間能夠經過 information_schema.tables表進行查看。只對myisam和aria表起做用 3 fast: 此選項檢查表是否已正確關閉,以及表或索引是否標記爲已損壞。在服務器崩潰以後,此選項提供了充足的信息用來判斷表是否損壞。只用於myisam和aria表 4 quick:不檢查刪除鏈。檢查刪除鏈須要花費很長時間, 但此選項可檢測大多數類型的損壞。只用於myisam和aria表。當使用change選項時,此選項默認啓用 (附上delete link的官文:In MyISAM tables, deleted rows are maintained in a linked list and subsequent INSERT operations reuse old row positions. 刪除的行的位置會寫進一個鏈表中,以供後續插入的新行使用。大概是這個意思) 5 medium: 經過校驗和對比來檢查數據和索引的完整性。 不多遇到此選項檢測不到的異常。爲默認啓用 6 extended: 此選項對錶執行完整性檢查。 若是表很大須要花費很長時間。 若是 check table 不能檢測到任何錯誤。則返回相似下面這行,好比這樣: 若是CHECK TABLE沒法指出錯誤,返回的結果集多是這樣:(原文是: If CHECK TABLE cannot correct the problems,由於check table 不是用來修復的,因此此處correct翻譯爲 指出錯誤 而非修正。我是這麼以爲) 咱們須要注意msg_type 和msg_text內容。 如前所述,當使用CHECK TABLE檢測到nnoDB表損壞後, 它試圖使服務器崩潰,以當即中止異常傳播。 若是發生這種狀況,咱們須要強制InnoDB在啓動時嘗試修復損壞的表。 repair table 語句 若是表損壞了。咱們無需停機便可嘗試修復。repair table語句就是用來完成這項任務的。該語句支持如下幾種引擎: myisam,aria,archive和CSV //* innodb 表不支持該命令 *// 語法以下: 和check table 相似。一樣適用於分區表,巧了!連語法也很像: 注意,後者不支持 USE_FRM QUICK選項僅用來修復index文件。因爲索引比數據文件更易損壞,故此選項挺有用。 EXTENDED ,索引以一種緩慢可是安全的方式來重建。可是 可能會生成許多垃圾行。所以,儘可能別用這個選項。 若是myisam表的索引文件 .myi丟失,則能夠使用USE_FRM選項。索引文件丟失頗有可能,好比repair table 語句修復失敗致使服務器崩潰並留下空的索引文件。雖然很小几率纔會發生。可是如前所述,咱們應該始終對損壞的表進行備份,而後再嘗試修復它們。 注意一點,對於USE_FRM來講,delete link也會被刪除,也就是說 將沒法使用OPTIMIZE TABLE語句回收未使用的空間。 此外,表的AUTO_INCREMENT值(若是有)將丟失。所以若是能選別的就選別的,儘可能別用USE_FRM。 此外,它絕對不要用於壓縮表,由於會對壓縮表形成損壞。能夠使用myisamchk或者aria_chk這樣的命令。 對於 NO_WRITE_TO_BINLOG選項,則不會寫入binary log。這在複製環境中想要避免把變動複製到slaves端時很是有用。此處使用LOCAL與NO_WRITE_TO_BINLOG意思相同。 修復CSV表 CSV引擎支持 check table 和 repair table語句。然而repair table 對csv引擎有着重要的限制:修復時遇到損壞行當即中止。 好比1000行的表,第十行損壞了. repair table僅能恢復前9行。不過咱們能夠備份一下該表,而後用文本編輯器打開,刪除第十行,重複修復過程直到全部沒損壞的行都被還原。可是這個方法不只不安全, 還慢,更重要的是容易煩躁。 使用 myisamchk 和 aria_chk 修復表 全部的MariaDB發行版都包含這兩個工具。它們能夠用來檢查或修復myisam或aria表。使用myisamchk的時候要求不能有其餘程序訪問表。換句話說,在運行myisamchk以前,須要鎖住相關表或者中止服務器。 //* myisamchk 和aria_chk工具不能應用於分區表 *// 語法以下: table_list參數能夠指定爲如下幾種方式 1 表名 2 表對應的索引文件名,表中的數據仍然會被檢查 3 能夠使用通配符匹配 經過強大的通配符來指定表名,好比下例表示選擇了 joomla數據庫中的全部myisam表 若是想指定全部數據庫中的全部myisam表,能夠這樣: 若是想指定db_1中的 customer和user表,能夠這樣: //* 除非被檢查的表處於和myisamchk或者aria_chk的同一目錄,不然必須指明具體路徑。這些工具可不知道MariaDB的目錄樹結構*/ 下面列出了幾個myisamchk和aria_chk的選項,至於其餘選項,咱們經過表格列出 1 --check:檢查被選中的表是否出錯。默認選項 2 --force:包含--check動做,若是出錯,則嘗試修復表 3 --repair:若是表出錯則嘗試修復。 4 --analyze:分析索引,相似 analyze table 下面的表格展現了myisamchk和aria_chk的其餘用來檢查表的重要選項(此處不譯) 當修復表時,能夠使用下列選項(同不譯) aria使用日誌文件和日誌控制文件來來修復損壞的表。aria_chk有幾個特定的選項用來指明如何使用這些文件來修復表(不譯) myisam 和 aria的自動恢復 myisam和aria支持自動恢復功能。當服務器開啓此功能時,服務器會檢查表是否被標記爲損壞或者而因爲服務器崩潰致使表 沒有正確關閉。若是檢測到,服務器會檢查表。若是檢查到錯誤,會嘗試修復問題。當aria的自動恢復功能打開時,只要aria表被打開,此套檢查動做就會執行。 因爲系統表空間在MySQL數據庫中而且爲myisam引擎控制,開啓myisam的自動恢復很是重要。全部生產環境服務器都應該開啓此功能。 若是表使用FIXED行格式,修復MyISAM表成功的可能性更大。由於這種格式下,myisam總能知道行從哪開始,從哪結束。 《MariaDB knowledge base》中對aria的稱呼爲:崩潰但安全的引擎。此處並不是說aria表不會出錯,意思是修改aria表的每條語句都具備原子性。要麼徹底成功,要麼徹底失敗。 myisam恢復能夠經過myisam_recover_options 選項來配置。能夠配置爲以下值,能夠使用多個,用逗號隔開便可: 1 off:關閉自動恢復 2 quick:進行快速檢查 3 force:最好可是比較慢的檢查 4 backup: 保留data文件的備份 5 backup_all:保留data和index文件的備份 6 default:同OFF 對於aria表的自動恢復來講,能夠經過 aria_recover選項進行調整,其可選值以下: 1 OFF:關閉自動恢復,默認值 2 QUCIK: 進行快速檢查 3 NORMAL:通常檢查 4 FORCE:檢查更狠點 5 BACKUP:保留data文件的備份 最安全的配置案例以下: 總結: 本章咱們討論了各類備份技術和工具。dba應該對這些備份方法瞭如指掌。由於每種方法都能在不一樣的環境下使用。 咱們討論瞭如何完成一個物理或邏輯完整備份。當有一個完整備份的時候,還能夠執行增量備份,它比完整備份更小更省時。隨後咱們討論和如何進行部分備份也就是不會包括全部的數據庫的全部表。至此全部的備份類型算是說完了。 在MariaDB 10以前備份 innodb表會很麻煩,須要服務器停機。咱們討論瞭如何備份和恢復innodb表。着重介紹了 percona xtrabackup工具。它專爲innodb作了優化,備份更快且無需停機。 當表損壞時,經過備份還原並不是惟一解決方案。咱們討論瞭如何修復表。操做步驟取決於具體的引擎。innodb恢復進程在服務器啓動過程當中調用。有些存儲引擎支持sql語句進行修復。還介紹了用來修復 myisam和aria表的兩個特殊工具。 下章中,咱們將會討論如何安裝和管理複製環境。 第九章 複製 MariaDB支持複製技術,複製技術用途普遍,但最經常使用的就是構建複製環境以增長數據冗餘度。複製沒法替代備份策略。若是讓slave端做爲master端的備份有可能會致使數據丟失。複製的另外一處用途就是讀寫分離。 上一章咱們介紹了備份。瞭解到這一主題的重要性。複製也算是備份的一種吧。它基於binary log。 本章咱們討論一下幾個主題 1 MariaDB中的複製如何工做 2 配置master 和 slave 3 加載數據到slave或master 4 配置master和slave 5 循環複製日誌 6 檢查slave端數據完整性 7 解決複製環境中的常見問題 複製概念 MariaDB支持內建的複製技術,此特性是一個很是古老可是又十分優秀的技術。初版是在MySQL 3.23.15中出現。當時MySQL甚至沒有innodb,也不支持union和視圖。固然初版的複製已經很是落後了。可是master端記錄sql語句到日誌而後把日誌發送給slave端執行這一基本方法沒變。現在複製環境變得原來越穩定強大了。 MariaDB複製技術基於binary log。binary log會記錄下全部修改數據庫的操做。binary log支持如下三種格式 1 語句 2 行 3 混合 對於 語句格式,條目由全部修改數據的sql語句構成。對於行格式,條目由全部因爲語句修改產生的結果構成的(相似變動向量?)混合格式記錄語句格式,可是若是有必要也會記錄成行格式。取決於格式,咱們能夠把複製定義爲基於行的和基於語句的。binary log在本章會詳細介紹。 MariaDB的內建複製技術叫作異步複製。也就是說master和slave之間的鏈接無需一直保持。 //* 極可能隨時中止複製來得到一個master端的快照。好比,若是想進行一個快速備份。當slave端再次啓動時,它會接收到master發來的複製環境中止那段時間產生的全部條目。對於slave端崩潰是同樣的 *// 客戶端能夠經過slave端進行查詢數據。讀負載重的系統能夠使用此特性。好比能夠經過把多個slave鏈接到同一master中來分散查詢請求。 每一個slave都有一個master。好比服務器A能夠是服務器B的master,服務器B也能夠是服務器C的master。若是B掛了,BC之間的複製會暫時中止,然而若是B丟失了數據,能夠經過C來做爲一個備份。固然在咱們這個例子中,C也能夠是A的master。這樣把複製環境搞成一個圈叫作 環形複製。它能夠在任意節點修改讀取數據並保證數據一致性。由於每次修改都會經過環形結構複製到環中的每一個節點。 主要缺點是沒有一個服務器能始終包含最新版本的數據。 MariaDB 10 支持多源複製。此特性容許slave端從多個master端複製數據。可是因爲MariaDB中沒有衝突控制,所以多個master必須傳送不一樣的數據。也就是說最好不要從多個master複製同一數據庫。多源複製容許你使用一臺機器或者有限的機器來從多個master中複製數據。 這種技術能夠下降硬件的成本。(我測試了一下,多源複製同一張表沒問題,可是千萬不能有主鍵衝突,若是有衝突,必然掛) 在複製環境中,最好全部的master和slave都使用相同的MariaDB版本。從老版本的master複製到新版本的slave中不可行。好比 5.5的master不能複製到 10.0中。重新版本的master複製到老版本的slave中一般沒問題,可是仍舊會致使一些問題。MySQL服務器能夠存在於複製拓撲中。 複製如何工做 本節咱們講解一下MariaDB中的複製是如何進行的。 尤爲是關於讀取操做將會使用哪些線程以及保留哪些日誌。這些知識對於之後的章節很是有用,包括如何配置master和slave以及如何管理復環境。 複製線程 在MariaDB 複製中,使用了三種複製線程,以下表: master和slave之間的鏈接由slave請求發起。當slave啓動時,它會建立SQL I/O線程,隨即鏈接到master申請得到必要的條目進行復制。 在master中會啓動binlog dump線程。此線程用來接收來自slave的SQL I/O 請求併發送其所須要的binary log 條目。在 show slave status 命令的輸出結果中,此線程叫作 slave_io_running. show processlist的輸出中叫作 binlog dump. SQL I/O線程不直接執行任何條目。它僅把條目寫入一個叫作 slave relay 的日誌文件中。 slave sql 線程從relay 日誌中讀取並執行日誌條目。 並行複製 在MariaDB 10 以前,每一個slave僅有一個 slave sql線程。由於正常狀況下master執行寫操做會使用多個並行線程,僅有一個slave sql線程有時並不能知足複製環境下的性能要求。 在MariaDB 10中,推出了一項叫作 並行複製的特性。oracle在MySQL 5.6中引入相似的功能。然而MySQL的用戶須要注意MariaDB和MySQL使用了不一樣的並行複製方法,並經過不一樣的方法配置。好比MariaDB中最重要的並行複製變量爲 @@slave_parallel_threads 。MySQL中並無。MySQL中的並行複製線程叫作 --slave-parallel-workers.在MariaDB 中並無。 並行複製由一個線程池構成,它能夠以並行方式應用日誌條目。每一個線程池中的線程叫作worker線程。到那時記住,並不是全部的條目均可以被並行應用。MariaDB 仍然會順序執行某些條目,這對於複製的正確性頗有必要。 此特性可選而且默認並未開啓。若是想使用的話能夠在master上配置,經過@@slave_parallel_threads 服務器變量便可。此變量指明瞭slave啓動時的worker線程數。會致使全部的slave都以一樣的worker線程數來從同一master中複製數據。固然,若是一個slave要從多個master上覆制數據,那麼全部的master上配置的@@slave_parallel_threads 變量必須相同。 slave log slave 端 須要記錄有關複製配置和當前進度的信息。這些信息必定不能丟失,即使發生崩潰。到此總結一下,每一個slave包含三種log 1 relay 日誌包含了從master端傳來的binary log。如以前所說,此日誌由 salve i/0 線程寫入,並由 slave sql 線程讀取。若是使用並行複製的話,則由worker線程讀取。 2 master 日誌 存儲了鏈接到master端的必要信息 以及master的binary log的座標,此座標由日誌文件名和接收到的最新的binary log位置構成。 3 relay 日誌的日誌。記錄了最新的relay 日誌條目的應用狀況。 relay 日誌老是寫入文件中。master 日誌信息和relay 日誌的日誌信息能夠寫入文件或者MySQL數據庫的系統表中。 即使在多源複製中,每一個slave的每種日誌都僅有一個。 選擇binary log格式 選擇binary log 格式是很是重要的。若是使用語句格式的,開發人員須要注意一些重要的限制。 能夠經過 binlog_format 變量來指定binary log的格式。若是不指定,默認爲語句格式。能夠經過 @@binlog_format 變量來查看當前使用的格式。 //* @@binlog_format 爲全局和會話級的動態變量。也就是說能夠在服務器運行時修改,不管是對全部鏈接或者是當前連接。然而最好別這麼幹,在master 上修改binary log的格式可能會致使複製中斷或者其餘一些意外。所以修改 @@binlog_format 須要 SUPER權限。可是在slave中修改日誌格式沒問題。 不能在存儲程序中修改 @@Binlog_format 格式。master和slave 沒有強制必須使用同一種binlog 格式。*// 基於語句的binary log 基於語句的binary log格式是最傳統的方式。當使用此方式時,日誌會記錄修改數據的語句。好比像 update, delete或者帶有where子句但有時並不修改任何行的replace都會被寫入log中。可是像select這樣不修改數據的就不會寫入日誌了。 statement 格式有一重要限制:只有肯定性的語句才應該被髮送到服務器。肯定性意思就是若是在相同的服務器中執行兩次,結果應該是相同的。 它們必然具備相同的效果。 固然這個限制對於不修改數據的語句無效,好比以前說的select,它既不會寫入日誌,也不會影響到複製數據。若是一條語句使用了當前的時間戳,當前的用戶或者隨機數,那麼就可能在slave端產生不一樣的結果。 若是使用statement 格式,MariaDB會檢測那些不安全的語句並拋出警告: 可是,MariaDB不會檢查使用的用戶變量的值是否爲肯定性。所以,當使用變量時,很容易出現插入一個非肯定性的數據而且不產生任何警告的狀況。 若是使用了存儲程序,尤爲須要注意這些地方。 另外一方面, MariaDB用於檢測非肯定性語句的啓發式技術不大好使。換句話說,因爲這裏使用的算法沒能正確分析一些語句,致使一些肯定性的語句也會拋出1592警告。此著名的bug能夠致使error log飛速增加。某些狀況下,仍是使用MIXED格式會比較好點。 此處列出什麼語句會致使結果爲非肯定的。 1 非肯定性函數,好比RAND(),USER().FOUND_ROWS(),ROW_COUNT(),LOAD_FILE() 都被認爲是非肯定性函數 2 用戶定義函數(由C語言編寫並安裝到服務器中) 3 使用服務器變量。這些值可能在slave端並不相同。也 有一些例外,但因爲目前沒有記錄,咱們必須依靠本身的經驗和邏輯去判斷。 4 帶有LIMIT子句的update(即使指定了order by也不行。算是一個bug吧) 5 AUTO_INCREMENT 列被修改, 而且該語句會致使觸發器被執行或者調用存儲的函數。 6 AUTO_INCREMENT 值自動生成,而且並非做爲主鍵出現。 7 在10.0版本以前認爲LOAD DATA INFILE也是不安全的 8 INSERT DELAYED會與myisam表衝突。(其餘引擎會忽略DELAYED子句) 9 語句中使用了系統表。這些表在mysql,information_schema,performance_schema庫中。在不一樣的服務器中它們的值是不一樣的。即使服務器接收的是相同的語句。 僅有read committed 和read uncommitted 能夠用statement格式。理由就是當使用 repeateable read 和serializable時。語句的執行順序會取決於語句的執行時間。好比由於有些語句會使用用戶鎖之類而使得語句執行的時間更長。 固然並非全部的非肯定函數都是不安全的。 緣由是有些函數產生的binary log日誌包含了準確複製的信息。好比date或者time函數,因爲binary log爲每條語句存儲了時間戳,因此它們是安全的。好比這些都是安全的非肯定函數: //* sysdate() 函數是時間函數中惟一一個不安全的。由於它返回的是當前函數調用的時間,並不是語句執行的時間。同一個查詢中的多個sysdate()函數調用會返回不一樣的結果。 所以,不可能複製它得到相同的返回值。不過這些限制只針對於 基於語句的binary log。可是,即使不適用複製環境,binary log中也不要包含非肯定語句。 畢竟備份仍是要用binary log的。 *// 基於行的binary log記錄 如以前所說,若是使用ROW格式,則binary log包含了數據的變動狀況。可是有些例外:有些操做會以不一樣的方式寫入日誌,好比: 1 ddl語句,好比 create table 和drop table 2 隱含地修改MySQL數據庫中的表的語句。好比像 create user 或者grant 這種。 顯式修改系統表的語句,如INSERT或UPDATE例外。 3 針對臨時表發起的語句。 以上這些例外會以語句方式記錄在日誌中,如同使用statement格式。好比,create ...select 語句會以不一樣的方式記錄:create table 部分會被寫成語句並以語句方式記錄,select涉及數據的部分則會以ROW格式記錄。 ROW格式的主要優勢是它沒有STATEMENT格式的限制:ROW格式中全部語句都是安全的。只要數據修改被記錄,語句產生的結果是否是具備肯定性跟數據變動狀況毫無關係。任何隔離級別均可以使用ROW格式,包括 read committed和read uncommitted。 固然,slaves端無需再次執行SQL語句。執行語句會涉及一些額外的動做,好比對行進行分組或排序或執行某些函數等等。應用ROW格式的變動對於slave端則會更直接,操做也更少。若是master端執行的語句很是複雜,則slave端能夠今後項特性中獲益。 固然也有不利之處:若是一條語句修改了許多行,row格式須要在log中寫入大量的數據變動。這會使得binary log變得很是巨大。若是使用複製環境,master端會發送更多的數據到slave端中。 然而,row格式比數據自己更加緊湊簡潔。一般寫入數據庫的數據都是以insert或者update方式進行的。若是要經過這種方式插入大量數據。statement格式會使得binary log變得異常巨大。固然,若是是多行語句僅對一行語句修改,則statement格式對負載沒什麼影響。 MIXED binary log格式 混合二進制格式 statement格式有許多限制,row格式有時又不利於工做負載。所以能夠使用MIXED格式。大多數狀況下,使用MIXED格式意味着絕大多數語句都會被記錄成STATEMENT格式。當檢測到非肯定性語句時,則會使用ROW格式記錄。以MIXED格式記錄的二進制數據叫作 binary injection.(二進制注入?)注意,只有read committed 和read uncommitted隔離級別能夠使用statement或者mixed格式。由於對於repeatable read格式來講, 鎖定事務的持續時間可能會影響其餘語句的執行順序。 這可能會致使master和slave之間出現差別。 存儲程序中的二進制日誌記錄。 存儲程序 (過程和函數)只有在肯定性且不修改任何數據時纔是安全的。所以當開啓binary log時,若是沒有以NOT DETERMINISTIC,READS SQL DATA,CONTAINS SQL或者NO SQL語句聲明,MariaDB會阻止你建立存儲程序。若是想強制建立,能夠經過設置 @@log_bin_trust_function_creators 來完成。然而這樣記錄的語句在statement格式下並不安全。 對於觸發器來講,不能使用 deterministic 或者not deterministic來聲名,不過若是它使用了非肯定語句,則一樣不安全。 另外,咱們必須記住,若是權限不一樣,SQL語句的行爲會有所不一樣。slave端使用擁有全部權限的用戶來執行全部的語句。 若是咱們不肯定存儲程序老是有權執行他們在master上嘗試的全部操做,咱們就不應以statement格式記錄。 配置複製 本節咱們來研究一下複製環境中master和slave上都須要配置什麼參數。 如下全部示例一樣可用在多源複製環境。固然仍是有些差別的,咱們放在後面再說。 配置複製環境至少須要如下幾步: 1 配置一個新的master 2 配置一個或多個slave 3 從master中加載數據 4 啓動slave 5 檢查slave運行狀況 咱們下面逐個講解 配置一個新的master 當安裝複製環境時,首先要作的固然是肯定至少一個master。其實就是選一臺有惟一id和開啓了binary log的MariaDB服務器便可。 首先須要給各個節點分配server ID。 server ID要求在複製環境中是惟一的。 它必須是4個字節的整數值,最小值爲1。若是沒有配置server ID或者設置爲0,表示關閉複製功能。 如以前所說,master中必須開啓binary log,它用來記錄master上的數據變動以發送給slave再現事物。 master的配置文件須要包含至少一下幾行: @@server_id 和@@binlog_format爲動態,可在服務器運行時調整 @@log_bin 變量並不是動態,更改此變量須要重啓服務器。 //* 最好把變動寫入配置文件,以備下次服務器重啓時能夠自動讀取,若有特殊狀況僅臨時調整的除外。 *// 而後,咱們須要一個帳戶用以複製工做, 嚴格來說,slave端的帳戶只須要 REPLICATION SLAVE 權限就夠。若是有些數據庫必定不能複製給它們,則不能授予該權限(???)。能夠給全部的slave端節點使用一樣的用戶。 他們甚至能夠使用與其餘客戶端共享一個賬號。然而這樣就須要把密碼存放在一個叫作 master.info 的文本文件中。最好給它們設置不一樣的密碼。固然,爲了提高數據安全性,每一個slave端用戶應該僅能鏈接到指定的主機。最好能經過SSL來進行鏈接。 下例展現瞭如何建立一個安全的複製帳戶 請注意,REPLICATION SLAVE權限不要與REPLICATION CLIENT 權限混淆。該權限應該授予那些須要進行復制配置,診斷的用戶,由於該權限會許可用戶執行 show master status 和show slave status 命令。 生產環境中,除非真的須要,不然儘可能不要用root帳戶。 關於安全和帳戶管理問題,能夠參考第五章。 配置一個新的 slave 端 在配置了一個或多個 master以後,如今須要配置slave了。此步驟爲配置複製環境必須的,即每次添加新的slave節點都要這麼作。 和master很像,每一個slave都須要一個惟一的server ID。 不過沒有必要開啓binary log。除非該slave扮演着其餘節點的master。若是不是這種狀況,開啓binary log對於備份固然也有用。可是會影響性能。 下例展現了slave中須要的最少配置:僅一個server ID就夠了 server-id =2 slave可能會扮演其餘一個或多個節點的master。這時,slave就須要開啓binary log來記錄從master上接收到的變動條目。 以便其slave可以檢索它們。默認狀況下複製條目不會被記錄。若是想複製它們,咱們必須開啓 binary log以及設置 @@LOG_SLAVE_UPDATES=ON。此變量非動態,更改須要重啓服務器。 下例展現slave扮演其餘節點的master的最少配置: 啓動slave 若是master上沒有數據。那麼配置複製就很是簡單。在填寫了上述配置參數以後。按照如下幾步執行便可: 1 在master上添加全局鎖。必須確保在啓動slave以前master是不能工做的。 2 獲取binary log的熱狀態。包括binary log的名字和最新的position(日誌的位置,相似oracle中的scn) 3 釋放master上的鎖 4 爲slave提供鏈接到master的必要的信息。咱們將經過change master命令來完成 5 在多個slave上重複操做。 下例展現瞭如何獲取master的binary log狀態。 如上顯示,master使用的binary log爲 binlog.000031 ,而且當前位置爲 323.slave 將會從該文件的該位置進行復制。 change master to 語句能夠用來告訴slave鏈接到哪一個master進行復制。基本語法以下: 此時,slave已經獲悉了鏈接到master上進行復制的全部信息,必要的權限在master上已經配置過了。一切準備就緒,如今只須要執行 start slave 命令便可。 這些鏈接參數之後能夠隨時更改,可是更改之後,必須臨時重啓一下複製。 固然,若是服務器重啓了,slave也會跟着重啓的。 檢查 slave 是否運行 能夠經過 show slave status 命令來查看slave 線程是否運行,好比: 輸出列很是多,此處截取一部分,只保留用來確認slave處在運行狀態的幾個重要參數。 slave_io_running 和 slave_sql_running 列必須爲yes。若是出現其餘值,slave_io_state和last_error能夠幫助咱們找出問題所在。好比若是鏈接出錯,則能夠看到相似一下錯誤。 從新配置已有的slave 有時咱們想對之後的slave從新配置。無論是想把原有的數據庫提高爲master,仍是過濾規則設置的不正確,無論怎麼說把,就是想讓slave從如今起忘掉以前複製的數據,從新開始。 在重啓以後,slave須要複製自master啓動以來的 binary log(這麼說是由於在當前兩端都沒有數據的大條件下,可是真實狀況手段不少,不必用這種追溯歷史的方法,除非及其特殊狀況,固然我想不出來)。所以必須抹除當前的狀態。reset slave 命令能夠經過刪除當前的slave日誌文件來抹除這些關聯。操做此命令必須中止複製。 好比這樣: 有時咱們須要用新機器來替換現有的master。無論是現有的master太慢仍是硬件壞了。無論怎麼說咱們都須要從舊master上把數據遷移到新master中。 咱們能夠選擇在slave已經運行而且鏈接到master時作遷移。第八章已經討論瞭如何使用mysqldump來導出導入數據。dump過程會自動複製到slave端。 除使用邏輯備份外還能夠經過複製文件來完成。此時,若是slave正在運行,備份是不會自動地被複制的。所以須要咱們把物理備份複製到slave的data目錄中。 從master上導入數據到slave中 複製環境並非靜態的。頗有可能隨時添加slave節點以經過大量MariaDB服務器的方式來解決數據冗餘或負載均衡等問題。這種狀況下,咱們須要把master的當前數據導入到slave中,而後slave才能夠進行復制。 能夠經過建立物理備份而後拷貝至slave的data目錄中來完成。常規的物理備份和用於複製的物理備份沒有任何區別。 固然也能夠使用mysqldump。這個工具已經討論過了,可是它還有一些參數能夠使得把數據還原至slave的過程更加容易。dump過程能夠從master或者slave發起。latter選項能夠避免master負載太重。 從master中導出數據 當從master上導出數據時能夠使用 --master-data選項。此選項會添加 change master to 語句到dump文件中,所以slave就能夠自動配置複製參數。 --delete-master-logs選項能夠在master上執行 purge binary logs命令,該命令用來刪除舊的binary log文件,本章隨後會講到。 從slave中導出數據 如今咱們想使用--dump-slave這個參數,它和 --master-data很是類似,可是在 change master to 過程略有不一樣。若是使用 --master-data,mysqldump會假定當前節點爲複製環境中的master,而--dump-slave則會假定當前節點爲slave,該slave使用的複製參數將會填寫到 change master to 語句中。注意此區別很是重要。(其實就是從哪一個角度看,一個認爲本機爲master,一個是把當前使用的master寫到dump文件中) 不過須要注意,當使用 --dump-slave時雖然在dump文件中會包含複製狀態,可是不會包含master的主機名和端口,所以還須要指定 --include-master-host-port 選項,以確保在change master to 命令中添加 master_host 和master_port 子句。此選項使得配置slave更加容易,除非dump從其餘slave中導出,或者不知道爲啥master的主機名和端口號都變了。 經過 --apply-slave-statements 選項能夠使得dump文件中在change master to 命令先後添加stop slave 和start slave命令。此參數在slave正在運行時很是有用,若是slave沒有運行,那麼start slave會使得複製當即開始,咱們最好先在slave啓動以前測試一下數據一致性,別讓它當即運行。 過濾binary log 條目 有時須要避免複製一些內容。能夠在master或單獨地slave中完成。(就這麼一句話。) SET SQL_LOG_BIN 語句 SET SQL_LOG_BIN 語句能夠用來在會話級開啓或關閉 binary log的記錄行爲。僅影響當前會話。若是設置爲0,則以後的語句將不會寫入binary log,也不會被slave進行復制。示例以下: @@skip_replication 變量 @@skip_replication 變量和 set SQL_LOG_BN 很是類似,然而在內部的日誌記錄上有些不一樣。它使得那些跳過複製的語句被打上skip_replication 的標記。slave仍舊會接收到這些條目,不過具體的行爲取決於 @@replicate_events_marked_for_skip變量。 1 REPLICATE :仍舊被複制,標記被忽略,此爲默認行爲 2 FILTER_ON_SLAVE: slave 會忽略這些條目,不過仍舊會接收並記錄它們,若是slave開啓了binary log的話,相應的標記也會添加到binary log中去。 3 FILTER_ON_MASTER: slave不會接收這些打了標記的條目。 從slave中過濾複製條目 slave中有三個動態變量能夠用來阻止表或庫進行復制。多個表或庫名經過逗號隔開。在改變這些變量以前,必須中止複製,三個變量以下: 1 @@replicate_skip_db:指定的數據庫不會被複制 2 @@replicate_skip_table 指定的表不會被複制,表名須要寫成 db_name.table_name的樣式。 3 @@replicate_wild_skip_tables: 和上個變量相似,不過它支持通配符。好比test%.% 則會阻止來自任何庫的任何以test開頭的表進行復制。 固然也能夠反過來配置,好比不容許複製全部表和庫,可是除了如下幾個參數指定的除外: @@replicate_do_db @@replicate_do_table @@replicate_wild_do_table 校驗 binary log 條目 從 MariaDB 5.3 開始,能夠在每一個複製條目中添加校驗信息。此特性默認關閉,由於它會修改binary log的格式,增長不兼容性。爲添加校驗信息,能夠設置 @@binlog_checksum =1 。開啓此選項會使複製更可靠,可是會對性能形成影響。 能夠在幾種狀況下驗證校驗信息 1 若是 @@master_verify_checksum=1 ,則slave i/o線程會對接收到的條目進行校驗 2 若是@@slave_sql_verify_checksum=1 ,則 slave的sql線程會參與校驗 3 若是在mysqlbinlog工具中使用了 --verify-binlog-checksum 選項則會對binary log進行校驗 更改binary log記錄條目方式的變量大多數是動態的。 配置並行複製 一般,一個數據庫進程會同時給多個客戶端提供服務。只要這些請求不經過行鎖或表鎖來保證數據完整性,它們就能併發執行。在第五章中咱們討論了併發控制。然而在mariadb10.0以前,slave僅使用一個線程用來複制接收到的全部條目。因爲這個限制,slave上的寫操做性能低下,尤爲是在master執行了許多非阻塞寫的時候。並行複製經過使用多個併發線程來進行應用複製條目解決這些問題。 如以前所說,並行複製默認不使用。若是想啓用,必須設定 @@slave_parallel_threads 變量爲一個大於0的值,在master上, 該值是全部slave將使用的並行工做的線程數。 下面介紹的幾個參數僅在使用並行複製時纔有意義 @@slave_parallel_max_queued 變量用指定數量的內存來緩存那些relay log中到目前還沒執行的日誌條目。當至少有一個worker線程空閒時,slave就會檢查該緩存來找到那些能夠並行執行的條目。 @@slave_domain_parallel_threads 在多源複製使用並行複製時很是有用。假設一下,當前有一個slave從三個master上覆制數據。假如其中的一個,好比說master1執行了一個要花幾個小時的語句。slave就得複製這個語句。同時,全部初始化的鏈接都會去獲取worker線程。可是worker線程已經關聯到master 1,而不得不等到這個很是長的語句執行完畢。當沒有worker線程空閒時,全部的鏈接就不再能從並行複製中獲益。 而@@slave_domain_parallel_threads 會阻止一個master獨佔線程池中全部鏈接。該變量決定了一臺master能夠得到的最大線程數。若是這個值不小於@@slave_parallel_threads ,則不起做用。可是若是比@@slave_parallel_threads 除以master的節點數還小。那麼有些worker線程則永遠不會用到。 該值應儘量高,以免在沒必要要時防止主鏈接分配線程。(原文寫了 to avoid preventing 這個雙重否認,實在難以理解,大體意思爲這個變量就是限定了一個master能夠用的最大線程數) 真實狀況下配置最優的@@slave_parallel_threads數會十分複雜。 它高度依賴於master的工做負載狀態。按照通常規律,能夠配置個比@@slave_parallel_therads小不少的值,在之後能夠逐步增長,直至找出最優值。 這些變量都是動態的,所以更改並行複製的配置無需重啓master。然而slave仍是須要臨時重啓一下。 讓slave慢點 先說一下爲何咱們想讓slave慢點複製。好比咱們想讓slave保持30分鐘的延遲複製來避免錯誤。假如咱們刪了一個表,咱們還有30分鐘的時間來從slave中還原。或者讓slave延遲一天,一週或者一月。可讓咱們比較不一樣時段的數據或者庫結構的變化。 MariaDB原生並不支持延遲複製。然而 percona toolkit 工具包中包含了一個工具用來在客戶端支持這一特性:pt-slave-delay.應該在全部須要進行延遲複製的slave上安裝此工具。該工具經過鏈接到slave而後按期檢查slave和master之間的延遲量來實現。當延遲過低,pt-slave-delay會讓slave中止複製一會。 如下幾個選項很是重要: 1 delay:設定想要延遲的時間。 --interval選項決定了間隔多長時間檢查一次。 2--run-time :決定該工具運行多久,若是沒有指定,則程序不會自動中止。默認狀況下,當程序終止再也不運行時,slave將會從新啓動。即使使用ctrl+c來終止程序也是一樣的。若是想更改此行爲,保持程序退出時slave持續運行,能夠使用 --continue選項。(相似循環結構中的break continue) 時間單位能夠經過數字+字母的形式來表示,好比 30m 表示 30分鐘 舉個延遲三小時每十分鐘檢測一次的例子: 多源複製 以前介紹的全部內容一樣適用於多源複製,不一樣之處在於每一個slave經過惟一id來關聯到一個主從鏈接。經過這個id能夠精確對每一個鏈接進行配置。(就是經過給鏈接起別名,以前沒有別名, 無法區分。) 好比咱們一般不想啓停全部的I/O線程,僅是想調整其中的一個。 這樣的話,全部的複製相關的sql語句都支持一個參數用來指定對其中的一個鏈接進行調整,好比: 固然也能夠一會兒啓停全部鏈接線程: start all slaves stop all slaves 當命令中沒有指明鏈接名稱的是誰,all關鍵字也不會出現,此時將使用默認鏈接。初始值爲空。能夠經過 @@default_master_connection變量來獲取和修改。 固然這個變量還可用於過濾鏈接。默認的會關聯到默認鏈接。如下語法用來爲當前鏈接指定過濾器。 connection_name.variable_name 好比,若是僅想經過master 1 來複制db 庫,而其餘的鏈接複製其餘庫。能夠這麼設置: set global master.replicate_do_db=''; (就是設置參數時候最好指明究竟是那一套複製。經過 「名字.參數」 來設定) 複製日誌 隨着服務器的正常活動和slave的不斷複製,使得master的binary log和slave的複製日誌愈來愈大。有必要循環使用舊日誌文件或刪除不須要的以避磁盤空間耗盡。本節講解如何完成。 循環 binary log 當前的binarylog名稱經過 --log-bin啓動參數設定。若是指定擴展名 則忽略該擴展名,而且僅使用基本名稱。默認 binary log會寫入data目錄。若是文件名沒有設定,則默認未主機名+ -bin 後綴。 max_binlog_size變量決定了當前文件的最大大小。單位爲 bytes。當達到這個大小時,binary log將會循環使用:當前的文件被重命名而且會建立一個新的同名文件。歸檔的文件遵循 <basename>.<prog_id> 格式,basename即當前文件的basename,prog_id爲六位數字構成的序列號。第一個數字爲 000001.同時包含一個<basename>.index的索引文件。索引文件名能夠經過 --log-bin_index來設定修改。索引文件爲人類可讀而且包含了當前已存在而且歸檔的文件,固然,當前使用的binary log文件也包含在其中。該文件不能刪除或手工修改。 binary log循環在服務器重啓時也會發生。除此以外,執行下述命令也會發生日誌循環。 flush logs flush binary logs 保留好當前已歸檔的binary log文件。它們能夠用於增量備份。對複製仍然有用:記住slave並不會當即應用接收到的日誌條目。它會又延遲,甚至有可能須要讀取幾天或幾個月以前的文件。 若是想查看當前存在的binary log文件,能夠使用 show binary logs 命令. 對於@@expire_logs_days 變量,若是爲非0值,則達到過時時間的文件會被刪除(天數)。配置該參數有必定風險,除非你能確保將被刪除的文件不會再被其餘slave須要。可是當選取了一個安全值時,還須要考慮slave崩潰而且停在一個文件上,或者一系列可能發生網絡等問題。這些問題都會致使發生延遲複製。 舊文件能夠經過程序進行刪除,使用sql語句便可。這種方法更快,可是須要作不少工做,所以通常都是經過crontab 腳原本觸發完成。 刪除一個再也不使用的日誌文件步驟以下: 1 執行 show slave status 命令 2 對每一個slave都會返回一行記錄。master_log_file列表示每一個slave當前正在讀取的binary log 文件。能夠經過腳本對文件名按照字母進行排序。 3 假定當前使用的最舊的文件爲 binlog-000050。 若是想刪除更久遠的文件,能夠使用該語句: purge binary logs to 'binlog.000050'; purge binary logs 命令一樣能夠根據時間來選擇,刪除指定時間以前的全部文件: purge binary logs before '2014-04-01 0:0:0'; 當一個運行的獨立服務器須要變成複製環境中的master時,能夠經過備份當前節點的數據,而後導入slave中。這樣binary log能夠徹底刪除,由於咱們無需再次複製該時間點前的數據。此時,再執行reset master。這個語句會徹底刪除全部的binary log 文件,清空binary 日誌索引文件,而且會從新建立編號爲000001 文件用以開始新的複製。 循環使用 relay log 至於寫入文件的 relay log,它的命名規則和binary log相同。默認狀況下 relay 日誌文件遵循以下規則: <hostname> -relay-bin.<prog_id>.hostname爲slave的主機名,prog_id 爲六位數字的序列號。能夠經過-relay-log 啓動選項來指定不一樣的名字。相似的也有 relay 日誌索引文件,命名格式爲: <hostname>-relay-bin.index。能夠經過 --relay-log-index 啓動選項進行修改。若是不特別指定,這兩種文件都放在data目錄中。 若是當前文件達到最大大小限制時,MariaDB會建立新的relay 日誌文件。最大relay 大小能夠經過max_relay_log_size 來指定。若是設置爲0,則大小與max_binlog_size設置的大小相同。 每次slave i/o線程啓動時都會建立新的relay log文件。如下命令能夠強制建立新的relay log: flush relay logs flush logs 當slave的sql線程執行了relay 日誌文件中最後一個條目的時候,這個文件就會被自動給刪除,除非它是當前文件,沒有辦法,也沒有必要干預這種機制。 slave的日誌狀態 master 日誌信息存放在data目錄中的 master.info中。能夠經過 --master-info-file啓動選項進行變動。relay 日誌信息存放在data目錄中的 relay-log文件中。能夠經過 --relay-log-Info-file啓動選項進行變動。 這些文件包含了show slave status 命令的輸出信息。然而,當slave線程運行時,該文件中的信息老是過期的,由於複製狀態的數據是存放在內存中。只有當slave中止運行時,該文件中的內容纔是最新的。 這些文件不會增加也不會自動循環更無需特殊的維護操做。 檢查複製錯誤 計算校驗和是最好的用來確保slave中數據準確的手段。這項檢查有如下兩種方案: 1 在加載數據到slave後,確保每項工做都OK。 2 處在運行狀態的服務器,須要按期檢查或者當咱們懷疑複製錯誤發生時 事實狀況更加複雜,由於在通常運行時slave都會和master有一個延遲。然而, 下面講解的工具可以經過等待slave 收到某一可靠的二進制日誌的事件自動執行此檢查。 至少有三種方法能夠實現: 1使用 checksum table命令 2 使用 percona 的 pt-table-checksum工具 3 對物理文件計算校驗和(僅針對備份) 有時咱們僅僅想檢查一部分數據的校驗和,而非整張表,這時能夠經過查詢來返回須要檢查的數據以計算md5校驗和。 checksum table 命令 該命令返回一個或多個表的校驗值,語法以下: quick 選項僅僅對 myisam 和aria表有效。這些引擎經過把 checksum或table_checksum選項設置爲1來計算一個活動的校驗和。使用quick選項,checksum table能夠返回一個活動值。 extended選項會經過讀取每一個單獨地行來計算校驗和,速度很是慢。 若是不指定選項,默認爲quick。 有些引擎不支持這些語句,此時將會返回null。 若是校驗和爲0,說明表爲空,看下例: pt-table-checksum 工具 和介紹過的其餘工具同樣,pt-table-checksum一樣來自於 percona toolkit。它能夠用來報告表的校驗和和行數。它對服務器性能影響不大,即使針對大表進行校驗。 pt-table-checksum對每張表進行校驗和計算。 表無需長時間鎖定和讀取。pt-table-checksum經過語句把大表切分紅幾個小的子查詢。基於服務器的響應時間,pt-table-checksum 組成會對當前工做負載不過重的部分進行查詢。此外,它會在每一個會話級設置 @@innodb_lock_wait=1, 所以當一個表長時間被另外一個會話鎖定時,它會斷開鏈接。 默認 pt-table-checksum工具也會檢測正在運行的slave,而且鏈接到它們去執行校驗檢查。該工具按期執行 show proceslist命令來監控已鏈接的slave節點。若是其中某些節點落後於master或者斷開,pt-table-checksum會處於等待狀態直到它們恢復。所以,該工具能夠說是用來按期檢查數據完整性的最佳工具。 在計算每張表的校驗和後,該工具會鏈接到slave節點而且一樣計算校驗和以認證表是相同的。而後它會輸出具體的校驗和和行數。整套流程完畢以前不會去檢查其餘表。 pt-table-checksum具備良好的容錯能力,它可能會由於一些不可控的錯誤而中止。此時能夠經過 --resume來重啓檢查,以前的進度並不會丟失。 文件校驗 在啓動slave以前 ,對物理備份拷貝計算校驗和是一個的好方法。Linux系統通常都有 md5sum命令,用它就能夠直接計算一個或多個文件的校驗和。好比: --binary 選項告知md5sum指定的文件默認包含二進制數據,或者若是指定了 --text選項,它會把文件當成文本格式,這僅用在 connect 或者 csv表以及日誌文件中。 查詢校驗和 某些狀況下,咱們想編寫一個僅返回最近插入或者最近修改的那些的行的查詢。 咱們能夠使用這樣的查詢來快速檢查最近複製數據時是否發生錯誤。能夠經過Linux中的 md5sum命令完成: 排錯 本小節着重講解當出現複製錯誤時的常看法決辦法 slave不啓動 當執行 start slave時,若是slave不能鏈接到master咱們是不會收到任何錯誤的。經過執行 show slave status才能夠知道 i/o線程是否正在工做。 若是複製沒能啓動,或者崩潰了。應該找出具體緣由並解決。如下幾個問題能夠幫助你解決不少常見問題,請在遇到錯誤時多問問本身: 1 slave端的版本號和master是否相等 2 master上是否開啓了binary log 3 配置文件中的變量名是否輸錯?服務器是否是並不是以複製身份啓動的。 4 master的地址,端口和登陸認證信息在slave中是否配置了 5 slave中配置了相應的帳戶了嗎? 6 帳戶有 replication slave 權限嗎? 7 防火牆是否配置正確 8 slave的磁盤是否滿了 當slave啓動後,除非收到 Stop slave 命令,不然不該該中止複製。然而,若是slave線程沒有運行,那麼slave極可能出現了複製錯誤。固然另外一個多是中了MariaDB的bug。 無論咋說吧,咱們應該從slave的錯誤日誌開始着手調查。而後, 對最新的relay log文件使用mysqlbinlog程序,基本上就能夠找出是哪條語句致使slave崩潰的了。 slave 滯後 經過在master上執行 show binary logs命令能夠查看當前有哪些binary log文件。若是文件有不少,那麼 至少有一個slave滯後了。 此處定義「太多」並不是嚴格上講:DBA知道他能夠忍受多少延遲或者是想要保持多久的延遲,但這取決於主服務器上的工做負載狀況。 若是咱們確認確實binary 日誌文件太多了,就須要找出到底哪一個slave出現了滯後。能夠經過 show slave status 命令來查看。經過對比 master_log_file和 relay_log_file列的文件名便可。 master_log_file列包含了當前哪一個binary 日誌文件正被slave的 i/o線程讀取。若是文件名太舊,說明 i/o線程出現了以後。多是網絡出現問題(無論是帶寬啊,環路啊,QOS等等之類),無論怎麼說吧, 使用鏈接壓縮應該能夠解決問題。固然咱們自身也要判斷選擇的binary log 格式是否最合適,由於這個因素會影響信息往返於網絡環境的質量。 relay_log_file 列包含了當前sql線程正在讀取的relay 日誌文件。 SQL線程滯後很常見。在 MariaDB 10 以前,該問題很是難以解決。不過到了MariaDB 10 以後出現了並行複製才大爲改觀。 若是開啓了並行複製, 最多見的問題多是查詢性能較差。不過能夠經過檢查master上的慢查詢日誌來找出問題所在。 總結 本章咱們討論了MariaDB中的複製技術 包括複製線程和日誌的詳細實施技術,以及討論了日誌循環。 即便在不使用複製的服務器上也須要進行這種循環,dba應該確保在全部slave節點成功複製完全部日誌以前沒有日誌被提早刪除。 咱們還學習瞭如何配置master,slave以及slave如何扮演master。還學瞭如何在slave和master上初始化數據以及檢查複製環境的工做狀態以及若是出現問題的通常解決思路。 下一章咱們將會討論表分區 第十章: 表分區 當表變得很是大時,查詢會變得很是慢 其中之一的解決方案就是表分區,這項技術經過把單張表分割成多個物理文件或表空間。每一個文件包含表數據的一部分,以此來提升讀取速度。由於讀寫單獨的分區會比處理大表更迅速。 本章咱們將學習到 1 MariaDB支持的分區類型 2 子分區 3 如何把每一個分區分紅多個文件 4 維護分區表 5 優化器如何利用分區 支持的分區 全部版本的MariaDB都支持分區技術。不過有如下兩種狀況是MariaDB不支持分區的。 1 若是MariaDB經過非支持分區參數進行編譯安裝---即 全部官方發行版都是這樣:分區技術默認不參與編譯。若是咱們經過源碼安裝,須要指定 --dwith_partition_storage_engine 參數 2 若是MariaDB經過關閉分區功能的參數進行啓動---好比啓動時指定了 --skip-partition。 這時只要重啓別再指定這個參數就能夠支持分區了。關閉分區功能也算不上什麼性能優化。 檢查當前安裝的MariaDB是否支持分區技術很是簡單。由於分區是以插件形式實現的,咱們僅須要查看 information_schema.plugins 表便可。 若是當前支持分區,則會輸出相似以上內容,若是當初編譯安裝時沒有加上分區支持參數,則上面的查詢不會返回任何記錄。若是自己是支持分區,而又是以關閉分區功能參數啓動的,則 plugin_status列會顯示 DISABLED。 分區在存儲引擎級實現,所以並不是全部的存儲引擎都支持分區。支持分區的引擎有如下幾個: 1 innodb 2 tokudb 3 memory 4 aria 5 myisam 6 archive 7 blackhole 對於blackhole來講。當一個分區表被轉換成blackhole,隨後又轉換成innodb時,這張表仍舊是分區表,也就是說分區的定義能夠被保存下來。但這項技術並不通用,由於這個轉換來轉換去的過程事不支持外鍵列和虛擬列的。 connect和federatedx 並不支持分區,可是它們能夠鏈接到遠程的分區表上。 當嘗試在一個不支持分區的引擎上建立分區表時,將會收到以下錯誤: 分區類型和表達式 分區是經過使用分區表達式對每行進行計算的值來完成的。分區類型是一種用於根據分區表達式將每一個行分配給特定分區的方法。好比,range類型會給每一個分區關聯一個取值範圍。當一行插入時就會進行分區表達式計算。該行就會被插入到屬於它範圍以內的分區中。 分區表達式 分區表達式是返回正整數值或NULL的SQL語句,對於時間列,在分區表達式中能夠被當作長整型值來返回。然而返回值是不依賴當前時區的,所以不容許使用timestamp和year列。 某些分區類型能夠使用返回不一樣數據類型的表達式,好比像date或者char,這些咱們隨後就會講到。 分區表達式必須返回肯定性的很是數值,不能使用存儲函數和用戶定義的函數,即使它們是肯定性的。 不容許使用 / 操做符,由於它會返回float值, 即便兩個操做數都是INTEGER也不行。DIV和MOD操做符是能夠的。位運算符不支持。 分區表達式應該儘量執行得快。理想狀況下應該只包含一列,最好是獲取整數值。真實環境下多列參與計算的狀況是不可避免的。然而複雜的表達式會影響插入更新和刪除的性能。 如下時間函數是通過優化的,能夠用在分區表達式中。 year() to_days() to_seconds() 其餘函數,好比 month() ,雖然並未優化,不過也能夠使用。 若是要使用HASH分區以實現良好的性能,那麼在表達式中僅能使用一列。 列值和表達式返回值之間也應該存在嚴格的關係: 列值的變更必定會引發返回值的更改。 舉幾個分區表達式的例子: id id mod 8 year(date) ord(name) 在隨後的章節,咱們將會研究如何使用分區表達式 索引和主鍵 對分區表來講,主鍵和惟一鍵有着很大的限制。每一個惟一鍵,包括主鍵必須被含全部須要參與分區表達式計算的列。 事實上,也意味着: 1 主鍵必須包含參與分區表達式計算的列 2只容許有限數量的惟一鍵 好比假定咱們想建立一張包含全部員工數據的表。非分區表應該是這樣的: 隨後,咱們想對這張表進行分區。無論由於什麼,雖然如今分區並不重要, 但咱們但願分區由YEAR(hire_date)來決定。然而,咱們須要對這張表修改。 1 第一種方法,咱們須要包含hire_date的主鍵,由於該列要用於分區表達式。然而 hire_date並不知足主鍵要求,由於它有不少重複值:多個員工可能同一天入職。所以,咱們的主鍵定義就變成了 primary key (id,hire_date). 請注意,此鍵如今比之前定義的主鍵更長。由於innodb表上的全部索引都包含主鍵,全部的索引都會變長。 2 第二種方法,惟一索引說不許對查詢有沒有用,可是它對約束是有用的,由於它會強制email和vat_id 保持惟一。然而在分區表中,全部的惟一鍵必須包含全部參與分區表達式計算的列。你能夠經過三種方式來完成。能夠在把 hire_date 列加到惟一索引中,可是沒法保證hire_date 列中的數據具備惟一性( 1中說了)。你能夠把惟一列添加到分區表達式,可是會致使插入和更新變得很是慢。最經常使用的解決方案就是避免使用惟一索引,這在咱們之後的例子中能夠看到。 (關於上面兩點我解釋一下,原文翻譯過來就這個樣子。說一下個人理解: 由於惟一鍵,包括主鍵必須被含全部須要參與分區表達式計算的列,因此若是想使用year做爲分區關鍵字,要麼把它作成主鍵,可是無法保證惟一性,因此須要用id列來拼湊一下。或者由於 email和vat_id也是惟一列,若是把hire_date 作成惟一列就好了,可是上面又說了惟一性很差保證。可是不表明不能作,若是這麼多列加入到分區表達式計算中,速度確定很慢,因此最好別使用惟一列) 對於key分區類型來講,主鍵是必須的。可是其餘類型的分區對主鍵卻是沒什麼限制。然而,沒有鍵的錶速度訪問會很慢。分區表不支持外鍵。不過普通非惟一索引卻是沒問題。 分區名稱 有些分區類型須要給每一個分區指定分區屬性。也有些分區只能指定一張表要分紅多少區。第一種狀況必須爲每一個分區指定名稱,後一種狀況,MariaDB會自動命名。 對於自動命名的分區,名稱爲p開頭後跟從0開始的分區步進編號。分區名稱大小寫敏感而且最大長度爲61個字符,比其餘對象的標識符略小。 當咱們指定分區名稱的時候,最好和自動命名的標準相似。然而在某些時候也能夠指定一些有意義的分區名稱。好比若是有張表,其中的一個分區包含了最近的數據,其餘則包含了歷史數據,那麼包含最近數據的分區名能夠指定爲 current.這項技術容許咱們根據需求來設定分區名稱。 分區類型 本節咱們將討論幾種分區類型,包括如何工做和建立它們。 RANGE和LIST類型很是類似,並支持相同的管理操做方式。對應的還有一些變體類型,好比RANGE COLUMNS和LIST COLUMNS。 hash和key類型很是類似,與之略有不一樣的兩個類型爲 linear hash 和 linear key。 range 類型 range分區類型爲每一個分區關聯不一樣的取值範圍。對每一個範圍來講,咱們只須要指明上邊界便可。第一個範圍從null開始。也就是最小的值。其餘範圍都是之前一分區的最大值做爲開始的。 看下面的例子: 最後一個分區會把值控制在2020以內。目前看來不算個問題,可是未來有一天仍是會出錯的。若是咱們嘗試插入一個範圍以外的值,則會收到以下報錯信息: 錯誤能夠經過指定ignore子句來忽略,不過行數據也不會被插入。 然而,下面的語法能夠幫助咱們插入一個範圍以外的值: partition p_name values less than (maxvalue) 此處括號可選。 上面的例子中,咱們建立了一張包含了文章的表。此表很是大,咱們想經過分區來加速查詢過程,由於該表包含很是老的文章,所以使用range類型貌似應該不錯,理由以下: 1 year(date) 類型能夠做爲分區表達式 2 通常查詢只會涉及到一個分區 3 一些查詢歷史的語句纔會會涉及到一個或多個分區 4 在未來,若是咱們想刪除很是老的數據,此時只須要刪除最老的分區便可。 list 類型 list分區類型和range很像,只不過list是經過列表列出每一個分區關聯的全部值而rang是經過範圍。每一個分區至少指定一個值。分區的順序和list的類型無關。全部可能值必須被顯示指定,而且沒有辦法把沒設定的值放到某一分區中。這點和range的maxvalue卻是不一樣(原文是 is similar to。。。)。當咱們插入一個沒有指定的值時,將會收到一個錯誤: 下例展現瞭如何建立list分區表: 這個例子中,language 列爲存儲語言信息的外鍵。此處沒設定外鍵的緣由就是不支持在外鍵上建立分區表達式。 此處分區表達式就是一個簡單的列名。可行的緣由是由於 language是一個正整數列。固然,char列也能夠的,好比包含語言的iso代碼的話。然而這種狀況下,表達式會把字符串轉義成爲數字。 儘管language列是整數,可是這些值不能按照邏輯排序(沒有排列的意義), 所以將它們分紅幾個範圍是沒有意義的。此處舉了幾個爲何使用list而不使用range的理由。 1 通常查詢極可能經過選擇語言來展現文章,所以經過語言分區可讓這樣的查詢僅使用一個分區 2 好比能夠查詢某個文章支持幾種語言。這將很是快,甚至無需關心是否訪問了分區表 3 若是某一種語言出現的比例比較高,那麼那種語言的文章就能夠單獨存放到一個分區。其餘分區能夠爲語言類型分組以控制合適的比例。 4 觀衆有可能常常閱讀至少兩個分區的內容。 和以前說的例子相似,若是咱們按日期劃分文章,固然這不太可能發生。經過language分區能夠幫助咱們把訪問最多的分區切分存放到不一樣的磁盤上去。這項技術在下面的 分區化的物理文件一節講解 5 若是某一語言數量增加明顯,能夠很容易的移動到新的分區中。 columns 關鍵字 range和list分區有兩個叫作 range columns 和 list columns 的變體。當使用它們時,就再也不只是單獨一個分區表達式了:關聯到分區的值是基於多個列構成的列表。這個列表在文檔中通常叫作 partitioned columns list (多列分區?)。 不容許使用函數,操做符或任何形式來進行列值的轉換。可是對於 columns類型來講,能夠使用用更多的數據類型: 1 全部的整型(但僅容許正數) 2 date和datetime 3 varchar,char,varbinary,和binary 不容許使用函數這點很是重要,此處沒法把非整型數據轉換成整型的。 以前使用的list類型的例子一樣能夠用在 list columns上,由於它僅僅是包含了一個列名 當須要經過多個列組合來使數據更好地分佈時,使用range columns類型會有效。如下例子展現了具體的語法: 這種分區策略反映了一個很是常見的狀況: 1 假定當前英文文章比其餘語言文章更多, 最合理的劃分彷佛是英文或非英文 2 在這些組中,咱們但願將最近的內容與非最近的內容分開。 注意不能使用year(date)函數。 因此咱們選擇將年份信息複製到一個字符串列中。 全部字符都是數字 只要全部值由四個字符組成,順序就不會改變。 //* 注意此處有一個限制--僅能在最後一個分區使用MAXVALUE關鍵字。好比若是在第二個分區使用 (1,MAXVALUE),看上去貌似行得通,可是會提示語法錯誤*// LIST COLUMNS類型對非整數列進行匹配頗有用。讓咱們回到那個使用LIST類型的例子中。咱們只能在language中存放成整型值,由於LIST中不支持雙字符的ISO代碼。可是LIST COLUMNS容許咱們這麼作: HASH和KEY類型 hash和key類型很是相似, 它們的目的是在分區之間對行提供更統一的分配。分區表達式返回的每一個不一樣的值會以相同的機率關聯到每一個分區, 一組連續值將被分配給不一樣的分區。 然而,若是某些值的分佈具備很是高的峯值。( 也就是說,有限的一組值常常出現)那麼就會致使某些分區會明顯比其餘分區擁有更多的數據。 若是惟一值的分佈是均勻的,則KEY和HASH類型的分區效果會更好。 對於hash和key來講,新行插入的目標分區由服務器自動計算,計算公式以下: MOD爲求餘運算 選擇hash仍是key取決於分區想要實現的功能。它們的異同有點相似 list和list columns。 1 HASH類型接受返回正整數或NULL的任何分區函數 2 KEY類型和LIST COLUMNS同樣能夠容許返回任何類型的值,但只能是單個列。 該列不容許進行計算 對於key類型來講,會返回一個計算過的hash值。hash值是經過PASSWORD()函數計算的來。該函數使用了SHA算法。 一般狀況下,建立一個hash分區表的語法以下: 其實大多數時候咱們只想肯定分區表達式和分區數。因此此處咱們使用year(date)做爲分區表達式由於全部同年發佈的文章將會存放到相同的分區中。某些狀況下,這使得咱們僅須要訪問一個分區便可。 下列語法也是能夠的: 容許咱們指定分區名稱。分區存放的物理文件路徑也能夠指定,咱們放在後面說。 若是想建立key分區,代碼示例以下: 上例咱們使用了自增列做爲分區關鍵字, 這能夠提供最統一的值的分佈 一樣,咱們能夠爲每一個分區指定名字,就像上面的hash分區例子同樣。 另外一方面,能夠使用更爲簡潔的語法,由於id爲主鍵,因此無需爲key分區指定列: LINEAR 關鍵字 linera hash 和 linear key 分區與hash 和key很是相似,不一樣之處在於使用了更復雜的算法來讓新的行插入到目標分區。linear公式對於正常的數據庫操做效率較低.然而它能夠使管理類操做更加快速。若是想要提高分區建立,刪除,切分,合併的性能。則使用linear關鍵字頗有效。 切分子分區 主分區能夠被切分紅多個子分區。僅支持一級切分,也就是說,子分區不能再被切分了。每一個分區必須設定相同的子分區編號。 只有RANGE和LIST分區的表能夠再進行子分區,子分區只能是HASH或者KEY分區。能夠使用 columns 和linear關鍵字。 使用任何其餘類型的組合會產生如下錯誤: 建立子分區的例子以下: 請注意,每一個子分區在整個分區中必須有惟一的名稱。能夠單獨指定文件路徑。 能夠使用更簡潔的語法,無需爲子分區指定名字或路徑: //* 子分區表達式必須顯式指定。主鍵默認用於key分區而非子分區。 *// 管理分區表 分區支持和常規表一樣的管理命令,好比修復和碎片整理,固然還有些其餘的功能。MariaDB提供了一套sql擴展工具來幫助咱們執行全部必要的維護任務。也提供了一些系統表來存放分區的元數據信息。本節將涉及此內容。 獲取分區信息 MariaDB提供了幾種方法來獲取分區信息。 show table status 的 create_options 列包含了分區表的相關信息。 獲取人類可讀信息的最容易辦法就是 show create table 命令。 information_schema.partitions表包含分區相關的內容。每一個子分區都擁有單獨的一行記錄。有些列的含義和table表的列含義相同。此處列出幾個和分區相關的列。 1 partition_method:描述了分區類型,同一張表的該列值相同。 2 partition_expression:描述了分區表達式。同一張表的該列值相同。 3 partition_name:分區名稱 4 partition_ordinal_position:描述了子分區的位置,從1開始 5 subpartition_method,subpartition_expression,subpartition_name和subpartition_ordinal_position: 這些列和上述幾個列相同,可是僅涉及子分區內容。 看以下查詢: 若是被分區的是innodb表,而且@@innodb_file_per_table=ON,則每一個分區或子分區都會寫入不一樣的表空間。也就是說分區和子分區能夠在 information_schema.innodb_sys_tablespaces 表中看到。 分區表的表空間和常規表空間文件的惟一區別是名稱格式,以下所示: 請思考下面的查詢: (是的,上面這個例子完了之後就本小節就沒了) 修改分區定義 MariaDB 支持用多種alter table 命令來修改,建立,刪除分區。其中 range 和 list 分區類型擁有豐富的命令集,以及提供了DBA應該注意的一系列警告。hash和key類型支持的命令集就比較少了。所以,不一樣的分區類型就要分別討論。 修改 range和list分區 好比如今咱們使用article表來進行分區試驗: 對於range和list分區類型來講,支持四種操做來對分區進行修改。 1 刪除一個分區 2 添加新分區 3 重組一個或多個分區 4 刪除全部分區 刪除已有的range或list分區會隨之刪除分區中的內容。好比,若是咱們想刪除p0分區,那麼article表中全部1990年以前發佈的內容都會丟失。刪除p0分區語法示例以下: alter table artivle drop partition p0; 添加新分區的命令很是簡單,但限制是不能與其餘分區的範圍或列產生重疊(原文爲不能包含其餘分區中已有的數據)。對於range分區來講,新分區只能添加到最後。固然,若是添加了 values less than maxvalue 這種分區,而且其中已經有數據的了話。那麼添加新的分區只要數據產生重疊,依然會失敗。還拿article表來舉例,添加新分區命令以下: alter table article add partition ( partition p5 values less than (2030)); drop partition 和 add partition 命令支持 if exists 和 if not exists 選項。經過這兩個選項,能夠使得你在刪除一個不存在的分區或者添加一個已存在的分區時不會產生ERROR。若是編寫到腳本中,能夠使得腳本更加完美。如下例子展現了刪除一個不存的分區的正確打開方式。 REORGANIZE命令容許咱們對分區進行分割或重命名。它經過一個或多個新分區的定義來替換一個或多個已有分區。其限制爲不能修改分區的範圍,除非是最後一個分區,只有它的範圍能夠被擴展。 這使得複雜的合併和拆分操做變得不可能,好比想把兩個分區切成三個或者把兩個分區合併成一個這種就行不通了。 下面的例子中,把p1分割成了兩個原始分區(爲什麼此處要用原始,原版?): alter table article reorganize partition p1 into ( partition p0 values less than (1990), partition p1 values less than (2000) ); 若是想把它們再次合併起來,能夠使用reorganize來避免數據丟失 alter table article reorganize partition p0,p1 into ( partition p1 values less than(2000) ); 讓咱們將p4重命名爲當前的一個: alter table aritcle reorganize partition p4 into ( partition current values less than (2020) ); 若是想無損移除一個分區的話,能夠使用以下命令: alter table article remove partitioning; 一般不建議這麼幹。然而 這樣作能夠使表處於容許咱們改變其分區類型或其分區表達式的中間狀態,或執行沒法使用REORGANIZE PARTITION完成的複雜重組。 修改 hash和key分區 本章咱們經過建立article的hash分區表來演示與以前的不一樣。 hash和key分區支持如下四種操做 1 添加分區 2 合併已有分區 3 變動分區屬性 4 刪除分區 在修改 range 和 list分區一節中,咱們已經討論瞭如何以及爲什麼要刪除分區。此處再也不贅述。 添加新分區很是簡單,語法和添加range分區很像。而且沒有條件限制。直接執行便可。好比這樣 alter table article add partition partitions 2; 這樣的語法也是容許的 alter table article add partition ( partition p8, partition p9 ); 這種語法無需爲新分區指定名字或路徑。若是想經過多個磁盤來提升性能,能夠看最後的分區物理文件一節。 hash和key類型不支持DROP操做: 因爲它們的性質,破壞分區及其全部數據是不可取的。不過能夠經過 COALESCE來把一個或多個分區的數據合併到其餘分區,這樣數據就不會丟失了。這項操做相對比較快。如下語法演示瞭如何從article表中移除兩個分區 alter table article coalesce partition 2; 注意,這個2是要刪除的分區編號。 對於這些分區類型來講,reorganize命令僅僅能夠用來重命名分區或改變一些選項。下例展現瞭如何重命名一個分區 alter table article reorganize partition p0 into ( partition p000); 分區和表間複製數據 此處描述的技術適用於全部分區類型,HASH和KEY類型除外,由於這兩種分區會使得邏輯行的行會分佈在全部分區上(logical sets of rows are distributed over all the partitions 是由於已有數據會分佈在全部的分區上?)。 range和list類型容許咱們使用一個或多個值來把數據以必定規律關聯到特定的分區中。一般分區表達式比較簡單。使得管理員經過查閱選項便可得知哪些分區存放了哪一種類型的行。 MariaDB 10.0 支持 經過 alter table命令來在分區表和非分區表之間交換數據。 /* 注意交換數據是雙向的。若是咱們僅想把一張表的內容複製到一個分區中,就須要先truncate 分區。若是想複製分區內容到表中,則須要先truncate 表 */ 如今咱們假定article表的定義以下: 下面例子中,咱們想要把current分區中的行復制到新建的recent_article 表中。首先先要建立一個和article表同樣結構的表。除了不是分區表以外,別的都同樣。最簡單的辦法是複製表結構而後刪除分區定義。以後就能夠開始交換數據了。 若是咱們不想清空原始表的內容,或者MariaDB的版本比10.0更老,那麼使用 select ..insert 或者 create table ...select 也行。若是想要在老版本中交換數據,就須要建立臨時表了。 當在MariaDB 10中複製分區數據,能夠用select的擴展選項,其僅僅會返回特定分區的數據。擴展選項在本章的查詢優化部分講解。可是如今先使用一下,很是容易理解。下面例子展現瞭如何把current分區中的數據直接寫入 recent_article表中而無需刪除原始數據。 管理命令 常規表上的管理命令在分區表上一樣適用。 一些ALTER TABLE子句可對一個或多個分區獨立進行操做,而不比非得是整張表。 下表顯示了一些管理語句 list 是操做中必須包含的一個或多個分區的列表。若是想選取全部分區,能夠使用all關鍵字 若是article 表有三個分區叫作 p0,p1,p2 如下三個命令是等價的 1 analyze table article; 2 alter table article analyze partition p0,p1,p2; 3 alter table article analyze partition all; 如下命令僅針對一個分區有效 alter table article analyze partition p0; 以上命令針對子分區皆不可用 對於 CHECKSUM TABLE命令來講,沒有對應的擴展語句,可是它能夠直接在分區表上使用。 分區的物理文件 若是 @@innobd_file_per_table =OFF ,則建立分區表時,全部分區都會存放到innodb系統表空間中,可是若是設置爲1,那麼每一個分區就會存放成不一樣的文件。 存儲引擎把索引和數據分開存放,好比aria和myisam,都會爲每一個分區建立一個數據文件和索引文件。 分區的數據和索引文件擴展名和非分區表同樣。文件名爲表名,後跟隨 #p#再加分區名稱。名字看起來大概是這樣: 和全部表同樣,被分區的表定義都會存放到 .frm中。可是它們還有個分區定義文件,叫作 ***.par . 好比假定有張叫作employee 的innodb表,有兩個分區,p0,p1。那麼它就會有以下文件: 對於ariab表,它的文件構成應該是這樣的: 對於子分區來講,每一個子分區都會建立一個獨立地文件。命名我就不翻譯了。此處假定emloyee 表有4個子分區 s0,s1,s2,s3. 子分區多個#SP#標識: 當設定過@@table_open_cache後,咱們必須記住每一個分區都須要一個單獨的文件句柄。 分區文件默認存放在data目錄中。固然能夠爲每一個分區的數據和索引文件指定特定的路徑。這樣能夠把文件分散到多個磁盤設備上,減輕單個磁盤的I/O。這項特性很是有用。咱們用分區技術的很大緣由就是由於能夠分散IO。語法大體以下: 這個例子中,若是沒有disk_x 目錄,則會自動建立一個,用它來存放分區0的數據文件。即使全部的分區都制定了非標準路徑,.par 分區定義文件仍然仍是在 data目錄中的。 /* 若是是分區表,在表級別設定 data directory 和 index directory沒什麼用,直接無警告忽略。*/ 查詢優化 若是分區表達式和分區類型已經被恰當設定,那麼大多數查詢僅僅會針對一個或少數幾個分區掃描便可獲得結果。 在大多數狀況下,優化器會找出哪些分區與當前查詢徹底不相干。這項優化叫作 partition pruning (分區修剪)。 若是用戶經過sql語句來指定掃描的分區列表,這就叫作 partition selection (分區選擇)。 /* 然而在MariaDB中,查詢永遠不會並行化。即使優化器指定必定要讀取兩個分區,而且這些分區處在不一樣的磁盤,相同的線程仍然只會依次掃描它們。 */ partition pruning 分區修剪 MariaDB中,分區修剪能夠用在range和list分區中,不適用於 range columns 或 list colums。當一條語句引用了分區表達式使用的列,優化器一般能夠根據查詢計劃來排除一個或多個分區。一般能夠排除到只剩一個分區。 優化器檢查如下語句中的WHERE子句,以肯定是否能夠應用分區修剪 1 select 2 insert ... select 3 replace ... select 4 delete 5 update 對於insert來講,優化器會檢查插入的值。對replace來講,where語句和新值都會被檢查。 當優化器分析where子句時,涉及到如下操做符是可能會進行修剪: 若是分區只包含分區表達式返回NULL,is null 和 is not null值的行,也能夠參與分區修剪。 能夠使用explain命令來得到sql的執行計劃。這點在第三章已經討論過。如今若是處理分區相關問題,就須要涉及explain的擴展選項—— partitions 關鍵字了。它會在explain的輸出中添加分區的列。其中包含了執行該語句會涉及到的分區名稱。經過添加partitions 能夠檢查分區修剪是否以及如何應用的。看下例。 下例中咱們使用 article表,以ID列的範圍做爲分區。 基於id排查的where條件使得該語句能夠經過分區修剪獲益。好比這樣: 只有相關的分區會被掃描。由於第一個分區包含小於5000的數據,優化器知道它不包含相關數據,所以p0不會被訪問,再看一個: 此項技術能夠在跨越多個分區的範圍的狀況下完美運行,能夠看到p0,p4分區都沒有被訪問。 若是查詢僅返回一行或只檢索一個值,此時應該僅訪問一個分區。看下面例子: 由於沒有分區包含咱們須要檢索的值。extra列中也清晰地告知咱們,在檢查分區定義後找不到符合要求的分區。所以查詢根本不會執行。再看一個: 這個例子僅僅展現一下在指定多個條件時分區修剪依然可用。 咱們也在list分區表上作一些查詢,不過僅僅用於說明分區修剪在list類型上的工做狀況。表定義以下: 如今,先看個例子: 僅有第一個分區包含1,因此其餘分區被修剪了。 看到哪怕是對不連續的分區,仍然可用。 在多個分區中檢索也可按預計的進行。 partition selection 分區選擇 分區修剪技術能夠幫助優化器自動決定哪些分區必定會被訪問到。在mariadb10.0中還提供給用戶一個能夠顯式聲名必定要掃描哪一個分區的技術:partition 子句 該子句能夠在任意表後面指定,下列語句都支持使用partition: partition子句的語法以下: partition_list 爲一個或多個分區名稱,以逗號隔開。子分區也能夠寫入列表,可是要將名稱與其主分區名稱相連。 好比對於tab表,如下命令會返回p0和 p1中的s3 子分區中的所有數據: select * from tab partition (p0,p1s3); 若是指定的分區不存在,那麼整個語句都會執行失敗並收到以下報錯: 現有分區能夠以任何順序使用屢次,這點對子分區一樣適用,即便它們的主分區也包含在列表中。(其實就是partition_list中的分區名稱能夠出現屢次,而且沒有順序要求。不管分區仍是子分區)。 由於分區修剪能夠自動處理而且在MariaDB中比分區選擇出現得更早,致使這項特性看起來沒什麼用。可是仍然仍是有很多優點,好比: 1 它適用於任何分區表達式 2 適用全部分區類型 3 可讓咱們指定子分區而且不會被自動修剪 4 假若有bug,分區修剪不可用了。 5 對於複雜查詢,它能夠令優化器明顯提速。 6 它有時能夠比WHERE子句更詳細 7 若是where子句不正確,會致使意外的數據損毀。添加額外的partition 子句能夠減少這種風險的機率。 8 相似地,能夠將PARTITION子句添加到添加大量數據的語句中,以免寫入不正確的值。這項技術使得在批量插入時,哪怕只有一行數據不知足要求,插入都會失敗。而且ignore子句不會起任何做用 9 它容許咱們一次快速查詢一個分區或子分區來分析整體數據分佈 總結 本章咱們學習瞭如何使用分區技術來優化大表 學習了MariaDB支持哪幾種分區類型以及如何編寫一個好的分區表達式。咱們經過幾張簡單的表學習瞭如何從不一樣的分區策略中獲益。還討論了子分區技術,學習了經過sql語句來管理分區。最後,還研究了優化器如何經過語句來排除不相關的分區以及如何強制服務器來掃描哪些分區。 下一章咱們將會討論在多臺服務器中如何實現數據分佈。 第11章 數據分片 本章咱們將會講解MariaDB中提供的三種重要的數據分片方式。 1 經過多路磁盤均衡IO 2 經過 FEDERATEDX或CONNECT構建簡單集羣 3 SPIDER引擎 經過多路磁盤分佈存儲文件 數據庫服務器的性能瓶頸一般爲I/O能力不足。讀取或修改不在內存中的數據須要訪問存儲設備。固然,你要是捨得花錢,好比買SSD之類的,那另當別論。然而不論你怎麼買買買,最終仍是會出現當前存儲設備速度太慢不足以知足與日俱增的高併發事物。解決這些問題的主要方法就是配置cache。第六章也說過了。然而,有時候常常訪問的數據集比RAM還要大很多。一樣日誌也須要頻繁地寫入,雖然一個好的配置策略能夠緩解這種狀況,但數據庫總歸還有大量的數據仍是要寫入磁盤的。 此外,存儲設備的容量有限。一個存儲設備確定塞不下整個大型庫。那麼本章就來說解一下如何經過多路磁盤設備來分佈存儲物理文件。 決定表文件的路徑 當建立表時,服務器默認會在data目錄中建立一個文件。默認路徑經過 @@datadir變量設定,注意並非動態的,僅能在配置文件或者啓動服務器時經過 --datadir來設定。 若是想給一張表的數據和索引指定不一樣的路徑,能夠經過 data directory 和 index directory 分別設定。單獨設定 data directory 不會影響到索引文件的路徑。 若是指定路徑不存在,則會報錯。 對於那些不能爲每一個索引設定路徑的引擎來講,好比innodb。強行設定 index directory 會生成以下警告。 看以下例子: data directory 和 index directory 僅能夠在建立表的時候指定。若是咱們嘗試經過alter table 來修改,則會收到以下警告: 對於分區表來講,data directory 和index directory 選項能夠爲每一個分區獨立設定。這一點咱們在第十章的時候已經說過了。 InnoDB能夠經過 @@innodb_data_home_dir 來設定一個單獨地目錄。默認狀況下 innobd使用 data目錄。 如第七章所說,innodb有一個 file-per-table 模式。其經過設定 @@innodb_file_per_table=ON來開啓。此變量在mariadb10 中默認爲on,老版本不是。若是開啓此功能,任何表均可以經過 data directory 選項來建立。若是爲OFF,那麼全部的表都會被存放到系統表空間。系統表空間存放在data目錄中。因此最好給存放系統表空間的目錄掛上高速存儲設備,好比raid或者ssd之類。 默認狀況下,data目錄中也會存放服務器日誌。日誌在第二章,第八章已經介紹過了,具體如何修改路徑,請查閱相關章節。 innodb 日誌文件 innodb在執行事物時有兩種特殊的日誌。 1 undo log 2 redo log undo log 用來在事物失敗,或狀態不完整時進行回滾。 數據的更改老是對數據自己(在緩存或磁盤上)進行,而不是單獨的副本。所以,一旦事物回滾,數據就會回退到被修改以前的狀態。undo log保留了原始數據的一份拷貝以及恢復所必要的信息。 如第六章所說,全部的修改一般會寫入到buffer pool中。內存中被修改過的頁叫作髒頁。這些頁須要被刷寫進磁盤以保證數據變動被持久化。然而在他們刷寫以前若是發生災難,好比MariaDB崩潰,或者斷電。 InnoDB必須保護數據免受相似事故的影響。爲避免不良影響,被修改的數據會優先寫入磁盤的redo log 中。若是發生災難,當MariaDB重啓時,innodb會重現已經寫入redo log的全部事物。 這些日誌必須被迅速寫入磁盤。由於大型事物會致使事物日誌很是多。所以最好是把日誌文件存放在不一樣的磁盤上。 這兩個日誌都會有許多非順序寫入,所以最好使用ssd設備。 配置undo log 默認狀況下,undo log 存放在系統表空間。若是想存放到不一樣的路徑,或者不一樣的存儲設備。那麼必須執行如下幾步。 1 @@innodb_undo_directory: 此變量決定undo log 在哪建立。 2 @@innodb_undo_tablespaces: 此變量表示寫入undo log表空間(文件)數。 若是其值爲0,默認undo log寫入系統表空間,其餘狀況下,undo log 會寫入由 @@innodb_undo_directory設定的目錄。最大值爲126.這兩個變量都不是動態的,而且必須經過配置文件或者 --innodb_undo_directory 和 innodb_undo_tablespaces 啓動選項來指定。 基於性能考慮,也能夠設定 @@innodb_undo_logs變量,此爲動態變量。若是performance_schema表常常顯示undo log上面有互斥鎖,那麼爲每一個日誌文件增長段的數量是個不錯的辦法,最大值爲128。 /* 須要注意的是,當服務器運行時,undo log文件的數量確定不會減小。也不該該去增長,除非咱們肯定有必要來減小鎖爭用。在生產環境上調整該參數最好仍是先測試好 */ (注意此參數經查閱資料和試驗,必須在數據庫初始化以前配置好。之後再配置會報錯。原文並未提到) 配置redo log redo log受如下三個變量影響 1 @@innodb_log_group_log_dir: redo log 文件存放的路徑 2 @@innodb_log_files_in_group:redo log 的文件數量 3 @@innodb_log_file_size:每一個獨立文件的大小。 這些變量都不是動態的。 redo log 的文件命名以ib_logfile 開始,後跟步進編號,從0開始。innodb開始寫入第一個文件直到它達到最大致積。當最後一個文件達到最大致積限制時,innodb會從新使用第一個文件。 全部文件的總最大大小都有限制,數值接近512GB。設定爲500GB比較保險。 默認redo log 存放在MariaDB的data目錄中。分別是 ib_logfile0和ib_logfile1。每一個文件的最大限制爲48MB。 若是爲了減輕主磁盤的IO,須要把redo log 文件移動到單獨地設備上時,不推薦改變log文件的編號。 //* 過大的@@innodb_log_file_size在mariadb5.5以前會致使恢復巨慢。可是新版本上不會了 *// FEDERATEDX 和 CONNECT 引擎 FEDERATEDX和 CONNECT 容許咱們在本地服務器上使用遠程節點的表。 本地的 federatedx和connect 表扮演着客戶端和遠程服務器之間的代理角色。當客戶端發送sql時,本地表會把sql發送到遠程服務器;當遠程服務器返回結果集時,表會把結果轉發給客戶端。 固然這並非在多個服務器間共享數據的最佳解決方案。spider引擎就能夠作得更好。然而,federatedx和connect引擎也有其必定的優點。 MariaDB knowledge base這本書說到,federatedx最先被cisco公司開發。由於他們的設備自己沒有那麼多的存儲空間,所以須要MySQL存儲引擎來訪問遠程數據。federatedx以前在MySQL 5.0中叫作federated。在MySQL 5.1中添加了許多功能。。由於MariaDB的開發者認爲oracle可能並不太樂意維護federated,他們就本身搞了一套衍生版,即如今MariaDB中的federatedx。這套衍生版的做者就是federated開發者本人。衍生版徹底兼容,而且還修補了不少bug以及帶來了一些新的特性。最值得一提的就是支持事物(前提是下層目標表支持事物)以及ODBC協議。 connect引擎在本書已經屢次說起。它基本上容許用戶像訪問MariaDB表同樣訪問各類外部數據源。包括非關係型數據源,好比文本文件;CSV,XML,HTML,和INI 等等。而且文件也能夠使用gzip進行壓縮。甚至有些奇奇怪怪的數據源也能夠獲得支持;好比在windows上,即使是目錄和MAC地址也能夠當作表來被讀取。與遠程數據庫服務器進行鏈接也是它支持的數據源之一。包括像MariaDB/MySQL的協議以及ODBC都是支持的。connect引擎在maraidb10中引入。 儘管federatedx和connect均可以傳輸遠程MySQL的表或視圖,可是它們不一樣的歷史背景決定了它們擁有不一樣的特性和優點。 下面列舉幾個federatedx和connect的特性 1 當建立本地表時,列定義能夠忽略,由於能夠直接使用遠程表定義。 2 能夠從本地表中排除一些遠程列。 3 本地表不能添加列,可是對於connect來講能夠添加虛擬列。 4 本地不會建立索引,這沒毛病,由於修改遠程節點數據無需訪問本地表。 建立federatedx 表 爲了向後兼容,federatedx在MariaDB中被稱做 federated。它屬於內建的插件,所以無需安裝也不能卸載。 讓咱們經過幾個例子來看一下如何建立federatedx表。首先須要在遠程節點上建立須要傳輸的表,遠程節點就叫作remote吧。什麼引擎都行。而後看例子: 而後在其餘服務器上建立federatedx表。本地節點就叫作local吧。代碼以下: 無需提供表的結構,由於它會根據遠程表的架構自行判斷。connection選項用來指定鏈接到遠程表的必要信息。此鏈接串的含義以下: 1 使用的協議: mysql:// 2 用戶名 user1 3 密碼 pwd 4 遠程節點的主機名或ip地址: remote_server 5 指明數據庫 : db1 6 遠程節點的表名 : user 若是未指定,則數據庫名稱和表名與用於FEDERATEDX表的名稱相同 //* 若是federated引擎版本很是老,則存儲鏈接遠程節點信息的選項是comment,而不是connection。壞處就是 用戶沒法將註釋關聯到FEDERATED表。當前版本的引擎都使用connection了。*// 定義遠程服務器鏈接 以前咱們展現過建立federtaedx鏈接一個遠程表的方法。很是方便。若是咱們想訪問遠程節點的多個表,咱們又不想重複輸入冗長的鏈接字符串時又該怎麼辦? 能夠爲遠程服務器或遠程數據庫定義一個鏈接(相似dblink)。經過create server 命令便可完成。經過這種方式建立的鏈接能夠用在全部須要訪問遠程表的引擎上。好比 federated ,federatedx,connect,spider都沒問題 如下是個create server的例子 沒有辦法來指定表名 而後就能夠經過鏈接來建立新表了: 此處鏈接字符串經過 定義的鏈接+表名便可。若是不指定表名,則假定要鏈接的表是和當前建立的表同名。 和存儲在MySQL 系統數據庫中的全部表同樣,存放鏈接信息的servers表一樣只能查詢不能直接修改。若是想查詢內容,能夠經過以下命令: 請注意,惟一支持Wrapper的只有MySQL,當前不支持Owner屬性。 以下命令能夠刪除一個連接 已有的連接不能被編輯,可是能夠刪除和重建。刪除或重建不會影響當前已有表。若是想更新表定義,就必須刪除並重建它。 建立 MySQL connect 表 connect 引擎支持多種類型的表。每種都容許咱們使用不一樣類型的數據源。數據源使得咱們能夠經過MySQL或ODBC來與其餘遠程DBMS服務器進行通訊。MariaDB和MySQL使用MySQL 鏈接協議,它屬於原生協議。ODBC能夠在任意支持ODBC標準的DBMS之間工做。此處咱們僅討論MySQL 鏈接協議。 建立federatedx表的語句也能夠用來建立MySQL connect表。 但不能定義任何索引: 和federatedx很像,connect一樣須要connection選項來指定鏈接串。 一樣也能夠只指定服務器名稱 connect引擎也支持dbname和tabname選項,用來指定遠程數據庫名稱和表名。 它們能夠與鏈接字符串組合,以下所示: 若是這時候connection裏面又指定了一次數據庫名稱和表名,則以鏈接串中所指定的爲主。 能夠指定視圖名稱來替表明名,舉個例子: 發送sql語句到遠程服務器 connect引擎容許咱們發送任意的sql語句到遠程服務上。很是有用,好比說你無需登陸遠程MariaDB服務器便可完成管理或者建立表之類的操做。 若是想直接發送命令到遠程服務器,那麼就必須建立一個特殊的connect表: 表和列名不相關,能夠任意定義。咱們使用了受管服務器的名稱,後跟_sql後綴。這樣看上去比較有邏輯性,若是咱們決定定義一個特殊的connect表來給全部的遠程服務器發送命令。即便咱們決定使用FEDERATEDX或SPIDER訪問遠程表,這也是有用的。可是,在設置這些特殊表的權限時,咱們必須謹慎。一般僅能被root或者那些有super權限的帳戶所訪問。 (這一段前言不搭後語,沒什麼乾貨,1 注意connect表命名要有含義,複合邏輯 2 注意權限問題) OPTION_LIST選項會使得connect引擎意識到這是一張不同凡響的表。其關鍵選項是Execsrs。Maxerr選項能夠用來設定能當咱們發送每條語句時,能夠從遠程服務器接收到的最大數量的錯誤和警告。 表中的每一列都有特殊的含義。 若是咱們使用有意義的名稱,則它們的功能會更清楚。列的名稱並不主要,列的含義是由FLAG來決定的。好比,重命名message列並不會改變它的功能,由於它的flag沒有改變。關於flag的含義,下面給出的表能說明一切 flag 默認是0,所以create table命令中,flag=0能夠省略。 下例展現瞭如何經過以前建立的表來執行一條sql語句: 執行的語句經過where條件發送而且經過statement列進行返回。咱們知道語句執行成功的話,warning應該是0.從message和number的表現狀況來看是沒有問題。 若是隻是爲了驗證create table語句在遠程節點上是否能夠執行成功,那麼能夠這樣使用connect表: 固然能夠一次性發送多條管理命令。使用IN操做符便可。會爲每一個執行的語句返回一行。好比這樣: 默認狀況下,只返回嚴重錯誤,它們包含在message(FLAG = 2)列中。 在大多數狀況下,這是足夠的,但有些狀況下,咱們傾向於評估每一個警告以調試消息。爲此,咱們能夠發送三個特殊命令到該表。connect引擎會解析這些命令而且並不會發送到遠程服務器: 它們會告知connect在結果集中展現notes,warnings和errors: 上例中,第一個note信息告訴咱們想要刪除的表不存在。最後的兩個警告告訴咱們由於myisam輸錯了因此自動設定爲InnoDB存儲引擎。 此技術不直接提供從遠程服務器檢索結果集。然而仍然能夠經過一些簡單的步驟完成: 1 發送create table ...select 語句到遠程節點 2 建立connect表設定新的遠程表 3 查詢本地表 注意,一旦遠程表改變,則本地表必須重建。除非列都同樣。 下例展現瞭如何檢索遠程服務器的版本號: 使用connect引擎合併多張表 另外一個很是有用的TABLE_TYPE選項就是tbl了。經過它能夠把多張相同或很是類似的表合併起來。tbl使得咱們能夠很是容易地把數據分片到多個服務器中。其方法爲定義一張本地connect表,經過tbl關鍵字來鏈接到多個connect表。對tbl表的查詢會把sql語句轉發給各個connect表,進而轉發到遠端MySQL表,而後數據會從遠端返回至本地最終返給客戶端。 注意tbl選項的限制:只讀。若是指定了tbl選項,則遠端表不能被修改,這就使得在不少狀況下達不到要求了。可是做爲在多個MariaDB節點間共享只讀數據仍是沒問題的。 建立帶有tbl選項表的例子以下: <table_list> 變量是以逗號分割的connect 表名稱的列表。每一個名字均可以經過 database_name.table_name來指定。若是數據庫名稱沒有,則假定該表位於與TBL表相同的數據庫中。 對於tbl表來講,技術上講,只能創建在CONNECT表上,它仍然能夠間接連接到使用不一樣存儲引擎的表,例如InnoDB或MyISAM。 這是經過建立指向這樣的表並在其上構建TBL表的MYSQL表來完成的(這是經過建立指向這些表的MYSQL表來完成的,並在它們上構建一個TBL表。翻譯成什麼的都有,我貼一下原文:This is done by creating MYSQL tables that point to such tables and build a TBL table on them. 並作一下解釋。意思是說tb表只能鏈接到connect表,可是若是想鏈接到本地表呢?好比innodb或者myisam,這樣先建立本地須要的表,而後建立connect表來鏈接到本地表,中間經過connect引擎作一個隔離來使得tbl能夠訪問常規的innodb或myisam這種。我是這麼理解的,由於套了一箇中間層,確定要比直接訪問慢,可是確定又比經過網絡訪問快。 )。可是結果將比直接訪問慢,由於將使用到本地服務器的鏈接。可是畢竟比鏈接遠程服務器要快。若是咱們但願經過多臺服務器(包括本地服務器)分發數據,這種技術很是有用 CONNECT引擎能夠解決使用其餘存儲引擎(如FEDERATEDX或SPIDER)沒法輕鬆解決的性能問題。假定咱們爲一家有幾家實體店的公司工做。每家門店都有本身的數據庫,其中有庫存產品,產品類別和最近交易等其餘數據。假設咱們要寫一個查詢,須要返回上週在全部商店銷售的手機平均數量。此時須要鏈接如下三張表: product_category,product,transaction. 可是,此JOIN必須分別針對每一個商店執行; 將一家商店的交易與另外一家商店的商品進行比較會不會出錯還很差說,具體要看系統是如何設計的,但毋庸置疑的是這樣須要大量的流量,速度會很是慢。要在門店的基礎上執行JOIN查詢,咱們能夠爲每一個門店建立一個MYSQL CONNECT表;該表將基於該查詢,使用SRCDEF選項,如如下代碼所示。這些表在查詢時將返回每一個商店的類別,產品和交易之間的關聯數據。而後,咱們能夠在這些MYSQL表之上構建TBL表,並執行返回所需平均值的查詢。這樣只有相有用的數據纔會從門店的數據庫發送到本地的MariaDB服務器。 能夠使用特殊語法來實現相同的結果,所以無需爲每一個遠程服務器定義新的CONNECT表。在tbl表定義時加上SRCDEF選項便可。好比這樣: SPIDER 存儲引擎 與FEDERATEDX和CONNECT引擎同樣,SPIDER也能夠像在本地服務器上同樣訪問遠程表。然而spdier引擎是專爲數據分片設計的。主要功能仍是經過訪問單張本地表來檢索多個遠程表。 使用表分區能夠在SPIDER中實現數據分片。若是把spider表分區,每一個分區能夠關聯到不一樣的遠程表。spider引擎很是適合range 和list分區,包括 range columns和 list columns。 spider支持常規sql事物和XA事物。前提是遠程表也支持。 SPIDER存儲引擎最初是爲MySQL設計的,與MariaDB一塊兒發行的版本會稍做修改,以利用MariaDB特有的功能。 spider的做者是 Kentoku Shiba. 項目地址爲: http://www.spiderformysql.com/ SPIDER引擎的工做原理 SPIDER存儲引擎本質上實現了本地服務器的優化器與對端存儲引擎進行通訊的過程。當優化器爲關聯到spider的查詢選擇了執行計劃後,spider會扮演成MariaDB客戶端,把這個計劃轉義成信令發送到一個或多個遠程服務器。 當使用spider引擎來向遠程服務器插入數據時,其內部使用了二階提交事物。使用一階提交的問題就是僅能保證關聯到一臺服務器的數據完整性。當全部修改都獲得響應時提交纔會生效。 可是假設修改涉及兩臺服務器,咱們將命令發送到這兩個服務器,而且沒收到錯誤。隨後,咱們在服務器1上發出提交,而且成功。 最後,咱們將提交發送到服務器2.若是此提交失敗,則出現了不一致。事實上,咱們要求的變動在服務器1上已經生效且不能被撤銷。所以一階提交不適合在多臺服務器之間執行事物。 兩階段提交事務模型與用於XA事務的模型相同。 用戶能夠發送 XA命令到,由於SPIDER徹底支持它。 可是,即便使用正常事務,SPIDER也會使用兩階提交來使變動在多臺服務器之間生效。對於這項技術,當服務器收到提交時,並不會當即應用變動。雖然 它知道事務完成,但它會等待第二次提交。若是任一遠程節點返回錯誤或不可達,spider就會在每一個服務器上回滾該事物,相關數據會被消除。僅當第一個提交在全部節點上所有成功後,spider纔會給全部節點發送第二個提交。第二個提交使得數據生效。 當查詢涉及多個SPIDER分區或多個未分區的SPIDER表時,它們會被分解成多個線程。 每一個須要被查詢訪問的遠程服務器使用單獨的線程。 考慮到這一點,DBA能夠經過添加多個分區來指向多個遠程服務器以使得擴展查詢並行化。 查詢結果由SPIDER緩存,直到它們被髮送到客戶端。不完整的結果集能夠存儲在遠程服務器或本地服務器上。 SPIDER存儲引擎在內存中維護遠程表和索引的統計信息。這些數據按期更新。和其餘引擎同樣,SPIDER經過訪問這些統計信息來選擇最優的執行計劃。 安裝spider引擎 SPIDER引擎在官方發佈的MariaDB中已經內建了,可是默認並未開啓。在使用以前,須要作如下幾步 1 安裝插件 2 執行install_SPIDER.sql 和全部插件同樣,SPIDER引擎能夠在服務器運行時經過 SQL INSTALL命令進行安裝。 install_SPIDER.sql文件的具體位置取決於MariaDB的發行版和操做系統。通常都在share子目錄中。這個文件會在MySQL數據庫中爲SPIDER建立所須要的系統表。 如下爲安裝SPIDER的過程 而後檢驗spdier是否安裝成功 建立SPIDER表 SPIDER存儲引擎支持特殊語法來指定遠程表的位置。 此語法與用於FEDERATEDX和CONNECT不一樣,必須在表選項中使用COMMENT 。 如下示例顯示如何建立一個鏈接到遠程表的簡單,未分區的SPIDER表。此處將使用咱們已經用於一些FEDERATEDX和CONNECT示例的user表: 若是table沒有指定,則選擇和本地同名的表。若是database沒有指定,則選擇包含當前本地表的database名稱。 咱們還能夠使用已定義的服務器名稱,以下所示: SPIDER存儲引擎能夠自動發現遠程表的結構,並建立一個相同的本地表。 所以,咱們能夠簡單地寫 SPIDER存儲引擎表在分區時很是有用。每一個分區能夠指定不一樣的遠程表。如下例子展現瞭如何建立SPIDER分區表 如下表選項可用於建立 使用SSL來鏈接到遠程服務器的 SPIDER表或SPIDER分區表(請注意斷句): 關於MariaDB ssl的詳細信息,參見第五章內容。 記錄查詢和錯誤 用戶針對SPIDER表的查詢能夠被寫入通常查詢日誌。固然, 若是由SPIDER生成的命令返回錯誤,那麼遠程服務器也會在錯誤日誌中記錄下來。這種行爲取決於@@general_log和@@log_error參數的設定。 然而,當SPIDER表查詢一個遠程表時,遠程服務器默認不會記錄命令。除非遠程服務器設置了@@ SPIDER_general_log=ON。 SPIDER命令將寫在通用查詢日誌中。 當SPIDER生成的命令在遠程服務器上返回錯誤時,經過設定@@SPIDER_log_result_errors=ON 能夠使得本地節點在日誌中記錄該錯誤。 在遠程服務器上執行任意語句 有些用戶定義函數(UDF)提供了一種簡單的方法實現對遠程服務器執行任意SQL語句的功能。SPIDER引擎中就有這樣的UDF函數。 和 MySQL connect的SCRDEF選項不一樣,這些函數會返回結果集。 //* 請注意,在任何狀況下,能夠調用這些函數來遠程執行SQL語句。 實際上,雖然它們誕生的目的旨在協助管理基於SPIDER的集羣,可是不適用SPIDER引擎也徹底沒問題 *// 淺析SPIDER_direct_sql() 函數 SPIDER_direct_sql()函數容許咱們對遠端MariaDB或MySQL執行任意的sql語句。查詢的結果將複製到臨時表中,所以須要在調用此函數以前建立該表。記住這張表必定是臨時的。 看例子: 讓咱們仔細看看這個函數,它有三個參數 1 咱們想在遠程服務器上執行的sql語句 2 想要存放結果集的臨時表名稱。注意表須要提早建立。此函數沒有給你臨時建立表的功能。 3 訪問遠程服務器必要的參數。語法和建立SPIDER表相同。一樣也能夠指定已定義的服務器名稱。 淺析 SPIDER_bg_direct_sql() 函數 當調用 SPIDER_direct_sql()事,當前連接會一直掛起直到遠程命令完畢而且結果集已經存放到指定的臨時表中。然而有時候咱們想執行一個長查詢,而且不想讓當前連接一直掛起等待它完成。此時能夠調用SPIDER_bg_direct_sql()函數。見名知意,它會在後臺執行sql。 至於語法,和SPIDER_direct_sql()一毛同樣。 總結 本章咱們講解了當I/O變成系統性能瓶頸時如何經過多路磁盤來提升性能。表文件和日誌文件能夠存放到不一樣的磁盤設備。尤爲是把innodb表和日誌移出系統表空間對性能提高巨大。 還討論瞭如何經過在多個服務器上分佈數據來均衡IO。MariaDB提供了三種存儲引擎來實現該功能 1 federatedx 2 connect 3 SPIDER federatedx引擎被設計用來訪問單張遠程表。CONNECT存儲引擎用於訪問各類格式的外部數據。SPIDER存儲引擎被設計用於使用MariaDB存儲引擎的API來實現表集羣。在以上狀況中,本地服務器和遠程服務器之間的通訊對於用戶來講是透明的,查詢FEDERATEDX,CONNECT或SPIDER表和查詢常規表徹底看不出區別。 在下一章,咱們將會討論如何經過galera實現MariaDB集羣。 第十二章 MariaDB galera cluster 本章咱們將會討論MariaDB galera cluster 。這項技術是由多個MariaDB節點組成的高性能,高可用的數據冗餘解決方案。如下幾點將是本章討論的主題 1 MariaDB galera cluster 的概念 2 安裝節點 3 啓動節點和配置集羣 4 使用 galera arbitrator 處理集羣腦裂問題 5 診斷和解決性能問題 6 經過使用 galera load balancer來分散集羣負載 MariaDB galera cluster 要點 galera 集羣,簡稱爲galera,是一種由MariaDB和MySQL組成的集羣。項目地址是: http://galeracluster.com/ MariaDB galera cluster是MariaDB官方發佈的集羣解決方案。要求MariaDB的主版本號必須相同。初版跟隨5.5發行,其餘發行版,好比 percona xtradb cluster 則是基於 percona server的。 MariaDB galera cluster 能夠經過MariaDB 的官方repo倉庫進行安裝和升級。或者也能夠從官網下載相應的Linux二進制安裝包。在MariaDB knowlegdge base中也包含了一部分galera的內容。當咱們在此書找不到須要的內容時,能夠去http://galeracluster.com/documentation-webpages/ 看看 galera 集羣概述 galera 集羣經過在節點之間使用多源同步複製來傳播數據。集羣中的全部節點都會接收用戶請求,看起來就像單臺服務器同樣。看成爲galera cluster集羣的一部分,咱們應該意識到到什麼能夠作,什麼不能夠作。最主要的限制就是galera只能運行在Linux上。而且只有innodb能夠完整地支持galera。有試驗代表對myisam的支持也能夠實現,可是最好別用。在本章隨後部分將會列出完整的限制。 集羣中的節點數量沒有下限或上限。然而,若是集羣須要保證高可用,則至少使用三個節點。 Galera不使用鬆散的一致性模型,例如大多數MySQL產品同樣使用完整的一致性檢查。它提供了DBMS一般所需的高一致性級別。無論用戶發送sql到哪臺節點,寫入都會以給定的順序進行。節點間沒有數據同步上的延遲。但在低速網絡中,須要注意網絡延遲,但它只應該涉及提交。而且在給定時間發送的查詢將始終返回相同的結果集,無論鏈接的是哪臺節點。這歸功於同步複製技術。 由於它的性質, Galera能夠用於幾個目的。能夠用在負載均衡,由於全部節點的數據都在同步增加。 若是節點在地理上很是遙遠, 客戶端甚至能夠與最近的節點交互,減小延遲。galera一樣也能夠把一個或多個節點用做數據的備份,避免在恢復正常備份時致使最近的數據丟失,或者也能夠當作一種傳統的複製系統,即全部的客戶端請求都在一個節點,其餘節點做爲slave。 //* galera中,每一個節點使用多個slave線程,mariadb10.0支持多線程複製,這項特性在5.5版本時引入*// Galera羣集適合雲計算,由於使用了節點間自動配置技術,使得縮放變得很是容易。 同步複製 全部MariaDB和MySQL的複製方案,包括內建的複製,都是異步的。異步複製保證了 master端上發生的寫操做都將傳播到全部slave中。 可是,不能保證何時會發生。實際上,在一些繁忙的系統中,主從兩端的數據延遲達到幾小時或者幾天都不是奇怪的。 同步複製的特性使得主從兩端的數據是同步的。事物同時進行不會產生延遲。如以前所說,同步複製有兩個重要意義:在主節點宕機以後不會產生數據丟失以及事物以相同的順序被全部節點執行。 然而實施同步複製對開發人員來講仍是有很強的挑戰性。傳統意義上說,它使用分佈式鎖或者二次提交技術。好比spider就使用二次提交。這些方法都比異步複製慢不少。galera使用不一樣的模型,即基於事物認證。當一個節點收到來自客戶端的sql語句時,執行該語句並把寫操做傳播到其餘節點而無需等待提交。事物的過程是並行的。 每一個節點應用寫入,但不使它們生效。若是修改爲功,節點就會確認這次操做。當第一個節點收到一個提交和全部節點的確認時纔會使寫操做生效並使全部節點提交。事務在傳播以前會從新排序, 這下降了它們在一些節點中由於衝突而失敗的機率(或者說整個集羣中)。 含有隱式提交的語句會與其餘寫操做隔離。該模型是近期在學術上關於對羣組通訊和重排序技術的實現。該學術的具體內容,見http:://infoscience.epfl.ch/record/32566/files/EPFL_TH2090.pdf Galera中的每一個節點內部仍舊使用innodb提供的傳統事物解決方案。這種機制會在每一個節點自動執行。所以,galera使用的這種複製技術也被叫作虛擬同步複製。 同步複製是經過wsrep完成的,MySQL和MariaDB都提供了該API。 Galera能夠被認爲是這個API的實現,並做爲了MariaDB和MySQL的插件。所以它也被稱做是wsrep實現的提供者,未來也許還會有基於galera開發的產品出現。 在 Launchpad項目中如是描述wsrep: 具體內容能夠參見:https://launchpad.net/wsrep 配置一個集羣 (安裝步驟大家看看就好,這些步驟還不如百度出來的帖子靠譜,可是理論知識比百度的強。譯者注) 本章將會討論如何配置一個集羣,不過先讓咱們看一下都須要提早準備什麼。 需求: 如以前所說,全部節點必須運行在Linux系統上。 硬件上卻是沒特別的需求;事實上,若是服務器能夠正常運行獨立的MariaDB服務,那麼也就能夠充當galera節點。在正常操做下。使用galera 複製佔用的內存很是少,幾乎能夠忽略。惟一注意的是,當從一個節點拷貝數據到另外一個節點的時候須要耗費大量內存。通常在新節點加入,或者當已經斷開的節點從新加入時。然而,當對節點進行硬件選型時,須要注意集羣的速度取決於集羣中最慢的那個節點。 兩個節點間的鏈接必須足夠快以應對負載需求。儘量保證MariaDB galera cluster運行在不含其餘主機的子網中。(節省背板帶寬),由於galera複製須要和集羣中全部節點進行通訊,網絡系統中不相關的流量將會影響整個集羣性能。一樣,阻止額外的主機能夠直接鏈接到集羣節點一樣也算一個安全策略。 固然,節點接收客戶端的請求須要更多的內存。咱們能夠使用多個節點來對大量查詢進行負載均衡。這項技術在本章的隨後部分講解。 安裝 MariaDB galera cluster包含在MariaDB的官方倉庫中。也能夠從官網下載通用二進制包。支持DEB和YUM工具安裝方式:debian,ubuntu,fedora,redhat和centos之類均可以。一樣也能夠進行源碼安裝。 須要安裝的應用包有: 1 MariaDB-galera-server :MariaDB galera cluster主程序 2 galera :wsrep 提供者 一些依賴包會被自動安裝。若是已經安裝了MariaDB-server 包,則它會被自動移除。 MariaDB galera cluster 節點間經過非標準端口通訊。默認使用如下幾個端口 1 4567 2 4568 3 4444 4 3306(標準端口) 若是安裝了SELINUX或者APPARMOR,默認它們會阻礙全部的非標準端口間通訊,妨礙集羣工做。此時,咱們須要設置正確的SELINUX或者APPARMOR策略,或者乾脆關閉它們。注意SELINUX會嚴重影響數據庫服務器性能。所以關閉它是個不錯的辦法。SELINUX在redhat的全部衍生髮行版中都是默認是關閉的,APPARMOR在ubuntu中默認是開啓的。 關閉SELINUX,執行以下命令: setenforce 0 關閉APPARMOR運行以下命令: cd /etc/apparmor.d/disable/ ln -s /etc/apparmor.d/usr/sbin.mysqld service apparmor restart 都須要root權限 若是有iptables或者其餘防火牆安裝的話,應該爲非標準端口設置訪問策略。 到此,基本上咱們算是已經準備安裝MariaDB galera cluster了。 從節點開始 啓動一個MariaDB galera cluster節點就是啓動一個MariaDB服務器。所以咱們能夠調用mysqld或者mysqld_safe腳本。 當第一次啓動一個節點的時候,咱們應該準備好配置文件,最小的配置文件示例以下: wsrep_provider=/usr/lib/galera/libgalera_smm.so default_storage_engine=InnoDB binlog_format=ROW innodb_autoinc_lock_mode=2 innodb_doublewrite=0 innodb_support_xa=0 query_cache_size=0 選項含義以下: 1 wsrep_provider選項是最重要的,它會告訴galera wsrep庫在哪,具體取決於你的系統。 2 由於不能使用innodb之外的存儲引擎,所以最重要的是設置default_storage_engine=innodb 3 binlog_format變量只能設置爲row 4 innodb_autoinc_lock_mode只能設置爲2 5 不能支持innodb的 doublewrite buffer和XA事物 6 不支持query cache 當啓動第一個節點的時候,咱們必須指定 --wsrep-new-cluster 選項、所以咱們能夠這樣啓動 mysqld --wsrep-new-cluster 若是節點崩潰,它必須從新執行以前的命令,由於它不會從新鏈接到已存在的集羣,所以,咱們應該使用mysqld_safe 啓動集羣。而且該節點必須當作一個新的節點加入到集羣中。 在一個節點啓動後,須要設置相應的權限。集羣中的每一個節點都必須容許其餘節點以root帳戶鏈接到本機以便須要的時候建立數據庫的拷貝。 此機制稱爲節點傳輸,詳細內容將會在本章的「節點傳輸」一節中講解。所以。咱們能夠執行一下命令受權 grant all on *.* to 'root'@'node_hostname'; node_hostname 須要替換爲真實的節點名或者ip地址。 集羣中的每一個節點由URL來定義。爲了往集羣中添加新節點,咱們須要指定至少一個當前正在運行的節點。 雖然一個節點一般是足夠的,但更好的作法是寫多個節點的地址。好比下面這個例子: 不須要其它信息。新節點便可經過該地址加入galera集羣。 在一個節點傳輸完畢後,咱們能夠檢查集羣是否正常運行。galera提供了一些表來診斷同步信息。全部的與galera相關的信息均可以經過 wsrep_ 開頭的表進行查看。好比這些: 請注意,上面這個查詢是在已啓動但未鏈接到集羣的節點上執行的。 下面這四個變量須要着重說明: 1 wsrep_ready:節點是否已經加入集羣並等待接收復制條目。 2 wsrep_connected: 節點是否鏈接到wsrep提供者 3 wsrep_cluster_status:節點是否鏈接到集羣中,若是沒有,則該值爲Disconnected。 4 wsrep_cluster_size: 集羣中的節點數 在新節點能夠開始複製從其餘節點接收的事件以前,當前的數據必須被複制到新節點。這一步叫作 節點預置或者狀態傳輸,具體在本章的節點預置部分講解 肯定節點URL 如以前所說,若是想啓動一個新節點或者崩潰後重啓,那麼必須指明其餘的節點地址。所以,dba須要知道如何來肯定節點的地址。 galera URL語法以下 1 gcomm: 生產環境用這個。 2 dummy:用來測試galera的配置。使用這個數據不會進行復制。 地址能夠是ip,主機名,也能夠指定端口號,默認的是4567,這樣寫也行: 192.168.96.213:4567 多個地址經過逗號分割。好比 192.168.96.213,192.168.96.217.能夠使用多播地址,例如IPv4或IPv6地址(最後一部分爲1)來標識子網中的全部主機。 有許多選項能夠指定,配置和wsrep_provider_options差很少。隨後咱們再說。這些設置最好都寫入配置文件。 最後舉幾個URL寫法的例子: 、 節點預置(Node provisioning) 關於 provisioning 的翻譯方法斟酌很久。參考 http://blog.csdn.net/catharryy/article/details/48661557 獲得「預置」這個譯法。 節點預置或者說狀態傳輸,會從其餘節點拷貝完整的數據備份到新的節點中。備份一般稱爲快照或狀態,以突出它是在精確時間點的一致版本的數據。發送其狀態的節點稱爲donor,接收狀態的節點叫作joiner。此操做會發生在新節點加入集羣或者某節點意外宕機重啓時須要接收最新的數據變動時。 有兩種主要的節點預置方法: 1 state snapshot transfer (SST)傳輸完整的快照 2 incremental state transfer ( IST ) 傳輸修改的變動 實際上,這些方法就是經過完整和增量備份完成的 State snapshot Transfer 此節點預置方法會被用在當新節點加入集羣時,由於新節點沒有數據。有兩種方法來執行SST: 1 mysqldump:此方法使用mysqldump工具生成能夠在其餘節點建立數據庫和數據的sql語句。此方法比較慢,由於它一般須要大量的網絡流量。在狀態傳輸期間,donor端會經過全局鎖使得數據處於只讀狀態。此外,此方法要求joiner節點處於運行狀態。若是使用了不一樣版本的MariaDB,或者不一樣的數據目錄結構,那麼必須使用mysqldump。 2 rsync,rsync_wan 和 xtrabackup:一樣用來把數據從donor複製到joiner中。此方法速度很快。使用rsync複製文件只須要複製已經被修改過的部分。rsync_wan方法使用了帶有delta傳輸算法的rsync,它能夠經過廣域網或者低速網絡進行數據傳輸,可是在其餘狀況下會比較慢。percona xtrabackup使得無需鎖表便可複製數據。rsync和xtrabackup已經在第八章討論過了。rsync比xtrabackup更快,可是它採用了阻塞方法。同時要求 innodb_file_per_table 和innodb_file_format在全部節點中配置相同。須要注意的是,若是使用了這些方法,那麼在傳輸以前joiner節點不能被初始化。 配置 wsrep_sst_method變量爲joiner配置須要的SST方法,好比這樣 wsrep_sst_method=xtrabackup //* SST支持可編寫腳本的接口。此特性容許咱們編寫腳原本定製數據傳輸操做以應對咱們特殊的使用狀況。這是一項很是有用的特性,可是它超出了本書的內容,有興趣能夠看galera的官方文檔,其包含了詳細內容 *// incremental state transfer 節點提交的全部寫入集都寫入稱爲Galera Cache(GCache)的特殊緩存。此結構能夠加速數據的I/O操做。當一個節點崩潰再重啓時, 由其餘節點執行的寫入集會徹底存儲在至少一個節點的GCache中。此時,增量狀態傳輸方法能夠使新節點更新數據。此方法有兩大優點。數據傳輸比SST快,由於它只發送給joiner最近更改過的部分。不須要對donor端進行鎖表。它能夠在傳輸期間繼續複製接收到的事件。 腦裂問題: 不管何種集羣,都會產生腦裂。爲理解腦裂的含義和可能發生的狀況,想一想一下,由數據庫組成的集羣分裂成了兩份數據中心。 或者,假設其中一個數據中心網絡鏈接被斷開。集羣如今分裂成了兩部分。然而每一個節點仍舊能夠正常工做,而且客戶端依舊能夠發送數據到節點中。若是集羣沒有提早裝備好處理這種狀況,兩個數據中心極可能會持續修改同一數據。當斷網節點的網絡修復後,極可能在數據層面產生衝突。一個集羣必須能夠自動地解決這些衝突;這被稱爲對腦裂問題的樂觀方法。若是集羣不能解決衝突,那就壞菜了。 Galera採用悲觀方法解決腦裂。它使用的技術稱爲權重法,它是所描述的法定一致性算法的變體(見書《Distributed Systems: Concepts and Design by George Coulouris, Jean Dollimore, Tim Kindberg, and Gordon Blair, Pearson Publication 》)。讓咱們看它如何工做。 集羣中的全部節點都保留集羣節點的個數。此計數不斷更新,若是有新節點加入,則此值增長, 若是一個節點正常關閉,它會與其餘節點通訊以代表本身將會離開集羣。然而,若是一個節點崩潰或者發生永久網絡故障,使得節點還沒來得及和其餘節點通訊就斷掉了。那麼該節點就會變得不可達。若是一個節點一段時間內不可達,其餘節點就認爲它不再會到達了。默認超時時間爲5秒, 可是能夠經過 evs.suspect_timeout選項修改。本章隨後部分咱們講解。 當一些節點檢測到另外一個節點不可達時, 若是集羣中的一半以上的節點仍然可達,那麼集羣的這部分仍然是主要集羣。此時該部分仍然能夠繼續工做。 若是隻有一半或少於原始節點數的一半是可達的,那麼集羣的這部分就成了非主要集羣。節點仍舊能夠接收鏈接並響應客戶端發來的請求。可是這些數據庫均爲只讀狀態。如以前所說,咱們能夠經過查詢wsrep_cluster_status變量來判斷當前節點是否屬於主要集羣。 //* 若是集羣只有兩個節點,當鏈接斷開時沒有任何一個分裂部分的節點數會大於另外一個。此時,全部節點都不屬於主要節點而且不能夠寫入數據 ,這就是爲何說galera集羣至少使用三個節點的緣由 *// 此算法保證了若是集羣裂成兩個或更多的分區,只會有其中的一個分區成爲主要的。任什麼時候候都不可能出現超過一個以上的分區能夠修改數據的狀況出現。 然而,咱們已經提過galera使用的仲裁算法叫作權重仲裁。也就是說能夠給節點預置不一樣的權重。當一個節點不可達時,galera不須要計算當前分區的數量,相反它會對分區的權重進行計算,統計沒個分區節點的權重總和。默認每一個節點權重爲1, 所以,分區的權重與其數量相同。 能夠經過pc.weight 選項來配置不一樣的權重。許可範圍爲0-255.若是權重被設置爲0,則該節點不會影響到權重統計結果。若是一組節點的權重最大,同時這些節點斷開了網絡鏈接,這組節點極可能會變成主要集羣。(下面舉個例子,實在以爲說得彆扭,可是又不影響主體知識。不譯了) 若是明確設置了節點的權重,就能保證不會有多個分區成爲主集羣。 //* 其實galera使用的權重仲裁算法比看上去要複雜得多。爲了清楚起見,這裏已經簡化了算法。能夠經過設置pc.ignore_quorum來關閉此算法。(注意enable這個參數是disable算法)。若是開啓了pc.ignore_quorum,則腦裂問題就會發生。此時咱們就得在沒有galera的幫助下來解決衝突問題。好比,若是能夠的話,須要覆蓋由分區執行的全部變動 *// galera 仲裁者 仲裁者是一種爲解決腦裂問題而出現的特殊節點。 它與羣集的其他部分通訊,就像它是正常節點同樣,但不復制任何數據。它的惟一目的是增長它能夠通訊的分區的數量——讓那個分區變成主要集羣。 好比咱們只有兩個節點,如以前所說,若是其中一個節點崩潰或者網絡斷開。餘下的分區就會變成 non-primary狀態。然而,若是咱們有仲裁者的話,仲裁者沒有崩潰,那麼和仲裁者鏈接沒有斷開的節點,是由兩個節點組成的,所以它就會變成主要集羣。 更復雜的例子是當galera集羣分裂成兩個數據分區,而且每一個數據分區都有相同數量的節點。 這個例子涉及到更多的服務器,幾乎和前一個相同;若是兩個數據中心之間的鏈接丟失,那麼它們中的任何一個都不會變成主要集羣。此問題無需添加新節點便可解決。咱們能夠配置一個仲裁者,它不處在任何兩個數據分區中。若是其中的一個丟失了和仲裁者的鏈接,另外一個能夠和仲裁者進行通訊,那麼能夠通訊的這個數據中分區就會變成主要集羣。 若是想使用仲裁者,咱們須要使用 galera arbitrator daemon(garbd). 其系統變量和wsrep參數與常規節點的選項相同。惟一例外是仲裁器中缺乏複製組中的wsrep參數, 由於它對沒有複製任何東西的節點來講沒有意義。 爲使用garbd,能夠在配置文件中寫: garbd -cfg /path/to/garb.cnf --daemon 若是想中止仲裁者,能夠kill掉 garbd進程。由於仲裁者不寫任何數據,因此沒什麼事。 配置集羣 MariaDB galera cluster節點能夠經過MariaDB系統參數和galera特定的參數進行配置。最重要的參數就是 wsrep_provider_options 。能夠用來配置wsrep參數,以逗號分割,爲動態變量 本節將會涉及最重要的變量和參數,完整的選項和參數列表能夠在 MariaDB knowledge base中找到。 galera最重要的系統參數 全部的galera特定的參數都帶有 'wsrep_' 前綴。能夠經過下面命令列出全部變量。 show variables like 'wsrep%'; 下面將會討論galera中的一些重要的系統參數。 集羣的通常設置 下面給咱們展現了galera中的通常設置: 1 wsrep_provider: wsrep 庫的地址 2 wsrep_cluster_address:填寫一個或者更多的集羣節點。如以前所說,設置此變量來爲集羣添加新節點是頗有必要的。此變量不是動態的。 3 wsrep_cluster_name:集羣的名字,節點會拒絕那些不屬於同一集羣中的節點鏈接到此。 4 wsrep_node_address :當前節點地址,此變量非動態。 5 wsrep_node_name :節點名稱,默認爲本機主機名 6 wsrep_on : 決定節點是否複製數據,能夠用來臨時暫停一個節點。 性能和可靠性 如下列出的參數能夠用來調整集羣的性能和可靠性 1 wsrep_data_home_dir :設置當前節點的數據目錄 2 wsrep_slave_threads : 決定能夠使用多少併發線程來進行復制。可是能不能加速操做還說不許。它對加速節點間同步很是有用。 推薦值最小值爲CPU內核數的4倍,可是最優值可能比這個更高。此變量不是動態,所以屢次重啓節點來測試性能是頗有必要的。記住,若是此值設置的比1大,那麼 innodb_locks_unsafe_for_binlog 必須設置爲1. 3 wsrep_causal_reads :若是該變量爲OFF,則會使節點應用寫操做數據集更快,而且開始執行新語句的時候無需等待更慢的節點。此爲默認行爲,可是它會在一段時間內致使一些不一致。設置爲ON能夠防止不一致出現,可是會增長延遲,默認值爲OFF 4 wsrep_max_ws_size_setd: 指定最大寫集大小,以bytes爲單位,非動態變量 5 wsrep_max_ws_rows: 單個寫集中最大的行數,非動態變量。 6 wsrep_retry_autocommit: 能夠幫助處理集羣間衝突。 它設置爲事務因爲這衝突而失敗時的最大重試次數。非動態變量 7 wsrep_load_data_splitting :能夠把LOAD DATA INFILE 分解爲多個事物,使得速度更快,可是有些不可靠。 設置SST: 如下設置會影響SST的行爲: 1 wsrep_sst_donor: 以逗號分割,表示能夠做爲donor的節點。必須使用節點名,不能使用ip地址。 2 wsrep_sst_donor_rejects_queries : 當前節點是否拒絕充當其餘節點的donor 。默認爲OFF,意味着能夠成爲donor。 3 wsrep_sst_method :使用SST方法 4 wsrep_sst_auth : 僅與使用的SST認證鏈接到正在運行的服務器有關,當使用xtrabackup或者mysqldump進行傳輸數據時,此變量應該包含用戶名和密碼以進行節點間認證,以冒號分割,好比 root:my_password。 galera 中的限制 1 wsrep_replicate_myisam: 決定是否能夠複製 myisam表。默認爲OFF。 2 wsrep_convert_lock_to_trx : 幫助應用程序從MyISAM到InnoDB過分。若是爲ON,則lock tables 和unlock tables語句會隱式轉換爲 start transaction 和commit。默認未OFF,若是開啓此特性,應當確認應用程序是否能夠正常工做。 3 wsrep_certify_nonPK : galera會自動爲那些沒有主鍵的表添加主鍵。默認爲ON 設置 wsrep 參數 許多wsrep參數均可以經過 wsrep_provider_options 變量進設置,以分號分割,好比這樣 set wsrep_provider_options ='option=value;option=value'; 和系統變量相同,wsrep選項也有動態的和非動態的。若是選項不是動態的,那麼節點必須在選項改變後重啓。 幾乎全部的選項名都有前綴, 其大體指示選項所指的組件。好比這樣 group_name.option_name 其中大多數的參數都須要對wsrep有很深的瞭解。咱們只在這裏介紹幾個最重要的,詳細內容能夠去MariaDB knowledge base 中查看。 1 base_host: 節點ip或主機名 2 base_port: 使用複製的端口 3 evs.inactive_timeout : 這肯定了在使用權重算法來處理問題以前,節點不可達的超時時間。 4 evs.user_send_window :決定多少包能夠一塊兒被複制。若是網絡很慢,應該增長此值,此選項動態。 5 gcache.dir :GCache文件的路徑,能夠把GCache 文件寫入到不一樣的存儲設備以優化性能。 6 gcache.mem_size : GCache的最大值,非動態 7 gcache.page_size: GCache的頁大小。非動態 8 gcs.fc_master_slave: 若是集羣中只有一個節點用來作主,能夠把這個值設置爲ON,意味着全部的客戶端僅僅會鏈接到該節點,非動態。 9 gcs.max_throttle:決定了節點預置是否會被加速,可是若是加速預置則會減慢常規復制操做,該值越低,狀態傳輸速度越快,若是設置爲0,則狀態傳輸完成以前,複製將會徹底中止。在galera中,減慢一個節點的複製也意味着拖慢集羣中全部節點的速度。 10 pc.ignore_quorum :設置爲1能夠關閉權重算法。除非你知道怎麼解決腦裂,不然最好不要這麼幹。 監控和排錯 galera提供了一些狀態變量以供監控每一個節點的狀態。和galera配置參數相同,每一個狀態變量都以wsrep_ 前綴爲開頭。能夠經過以下命令查看這些狀態變量: show status like 'wsrep%'; 此處至少有兩種辦法來監控MariaDB galera cluster。 1 使用 galer cluster nagios插件,它由 FromDual開發和維護。能夠經過 http://www.fromdual.com/ 進行下載。本書不涉及此內容,有興趣能夠去它的官網上看。 2 使用galera 自動通知 通知腳本 能夠經過使用wsrep_notify_cmd 來設置shell命令或者腳本。當節點狀態改變時會自動觸發腳本。能夠添加一些額外的參數以在通知運維人員時提供更詳細的信息。此腳本能夠利用這些信息作出相應的反饋,好比把事件寫到文件,或者MariaDB表或者給管理員發送數據庫的主要問題的描述。 通知腳本語法以下: 解釋以下: 1 command :wsrep_notify_cmd中特定的命令 2 new_status :當前節點狀態 3 state_uuid :最新狀態變動相關的UUID 4 --primary :此參數指示節點是不是主羣集的成員 5 members_list : 逗號分割,鏈接到集羣分區的節點列表。 下面是一個不是頗有用,可是很具體地展現瞭如何寫一個通知腳本的例子。如下腳本爲bash腳本。若是 node1 變成非主要節點時會給dba發送郵件,腳本以下: 爲了讓galera調用此腳本,能夠設置以下參數 set @@global.wsrep_notify_cmd ='/path/to/notify.sh'; 檢查狀態變量 能夠按期執行幾個檢查來驗證集羣的完整性,這些檢查分爲四類 1 cluster health:經過檢查集羣健康狀態,能夠知道集羣是否被分割或者是否全部的節點都正常運行 2 individual node health: 經過獨立的節點健康狀態檢查,咱們能夠知道被檢查節點是否正在運行,若是不是,能夠找出具體的緣由 3 replication health: 即使全部的節點都正常運行,咱們仍想要確認一下複製的延遲是否在可接受範圍以內。 4 network perfirmance: 網絡通訊的速度 集羣的健康狀態: 第一個須要檢查的集羣狀態變量就是 wsrep_cluster_size 。若是該值小於真實的節點數,要麼至少有一個節點掛掉要麼就是集羣產生了分裂。在一個節點上檢查該變量就足夠了。可是若是發現該值實在是過低了,那麼能夠經過檢查其餘節點來分析具體的緣由。 在這種狀況下,咱們能夠經過檢查每一個節點的 wsrep_cluster_state_uuid 和wsrep_cluster_conf_id 兩個變量。這些值都是UUID,在正常條件下,全部節點都是相同的,若是兩個節點有不一樣的 wsrep_cluster_state_uuid,說明它們不屬於同一集羣。若是這些值相等,可是wsrep_cluster_conf 不一樣,說明集羣被分裂了。 若是集羣被分裂,咱們須要鏈接到每一個分裂集羣中的節點去確認當前節點是不是主要節點。咱們能夠經過檢查每一個節點的wsrep_cluster_status狀態變量來判斷。若是至少有一個節點不屬於主要分區,則集羣被分裂了。 獨立節點的健康狀態 若是集羣的規模很小,咱們能夠檢查每一個節點來找出運行不正常的節點。 確認當前節點是否運行的最佳辦法就是查詢wsrep_ready變量。若是節點處於健康狀態,該值必定爲true。若是不是,那麼咱們必須找出具體緣由。 wsrep_connected 狀態變量表明瞭wsrep庫是否正產運行以及是否鏈接到了MariaDB。也就是說,極可能由於配置錯誤而致使wsrep沒有被加載。此時,咱們須要檢查像wsrep_cluster_address這樣的配置參數。 若是wsrep_connected 爲true。咱們能夠檢查wsrep_local_state_comment 變量,若是它爲'Joining','Waiting for sst'或者 'Joined' 說明節點仍舊鏈接到了集羣。對於龐大的數據庫或者低速網絡,‘Waiting for SST’會花費不少時間。 複製的健康狀態 在同步複製環境中,集羣不會比最慢的節點更快。這是由於集羣運行一個事物,就不得不等待全部的節點都運行完畢。所以,常常檢查wsrep_flow_control_paused變量就頗有必要。該變量值範圍爲0到1,表示當前節點花費在等待其餘節點完成事物的時間。若是該值不是很接近0,則說明咱們有延遲問題。 此時,咱們能夠經過以下兩個變量來找出運行緩慢的節點: 1 wsrep_flow_control_sent 2 wsrep_local_recv_queue_avg 運行速度慢的節點這兩個變量的值都比較大。 若是某個節點很慢,能夠嘗試增長複製進程數。固然也不要忘了檢查MariaDB的常規性能問題,好比說佔用率不正常的 buffer pool 網絡性能 若是沒有節點比其餘節點明顯更慢而且咱們仍然對性能不滿意時,那麼總體的性能瓶頸可能就出如今網速上。若是想確認是不是該緣由,能夠檢查wsrep_local_send_queue_avg 狀態變量。低速網絡會致使產生大量被隊列的消息。ping工具就能夠簡單地確認網絡性能優劣。或者使用iftop來給咱們展現網絡流量,來確認帶寬是否被佔滿。 網速低的緣由有不少,可是該主題在本書中不會涉及,此處只說起幾個對網絡性能有益的建議 1 galera集羣須要單獨的網絡環境。多餘的通訊會致使複製變慢 2 檢查系統防火牆配置,最好關閉 3 若是緣由很難定位,能夠考慮一下物理層的緣由,有時咱們可能會發現一條長的電纜被捲起來,或者它靠近磁源。電磁干擾可能會減慢網絡速度或使其不可靠。 負載均衡 負載均衡能夠應用於任何計算機集羣的優化包括平衡節點之間的請求,以使它們都具備大體相同的工做量。客戶端鏈接到負載均衡器,它能夠像代理同樣從新定位會話。負載均衡器開源,非開源都有。大多數是通用的均衡器,旨在與任何通訊協同工做。所以咱們能夠用在web服務器,文件服務器等等任何服務器中。但並非全部的負載均衡器都與數據庫服務器配合得很好。 在本書中,咱們將着重講解一下專爲galera cluster集羣設計的負載均衡器—— galera load balancer Galera Cluster的侷限性 MariaDB galera cluster 由於設計原理致使會在應用上有些侷限性。開發人員和dba應該明白有些在MariaDB上能夠使用的特性在galera中是不可用的。 首先,如以前所說galera只能應用在Linux系統中。 galera目前僅支持innodb存儲引擎。實驗環境下myisam也是支持的,可是默認關閉。能夠經過把 wsrep_replicate_myisam 設置爲1開啓。galera團隊不鼓勵在生產環境修改該變量。其餘存儲引擎在galera中不可取。 獲取顯式鎖的語句,像 select ..for update, select ...lock in share mode, lock tables 或者 flush tables .. for exporty 都是不支持的。這使得MyISAM的使用更不理想。 SERIALIZABLE隔離級別會使得全部簡單的查詢轉換爲鎖定查詢,一樣也是不支持的。緣由是讀操做和鎖不會經過集羣傳播。因此這些鎖只能在一個節點上得到,會形成一些潛在的衝突。可是有個例外:若是全部的客戶端都鏈接到同一個節點,那麼lock是沒有問題的。 galera被設計用來複制那些有主鍵的表,所以對於一些沒有主鍵的表會產生各類問題,好比delete不支持,XA事物也不支持,innodb 雙寫緩衝會被關閉,而且query cache也不支持。 在MySQL 數據庫中顯式修改一張表是不支持的。除此以外,general query log 和error log也只能寫到文件中。 (本小節在百度中很難找到具體說明,尤爲是對不能LOCK的緣由沒有合適的解釋,只是列出了galera的限制。結合百度的內容和本小節的知識,總結以下:1 因爲lock沒法傳播,因此與鎖有關的內容都須要格外注意 2 若是僅有一個節點用來處理鏈接,那麼限制會少得多) galera load balancer 負載均衡 galera load balancer 是FromDual開發的第三方插件,官網以下 http://www.fromdual.com/ 和galera 同樣GLB也只能運行在Linux中。 它由一個叫作glbd的程序組成 GLB沒有客戶端管理程序,若是想發送管理命令,好比添加刪除節點,能夠使用nc工具。nc工具與tcp進行通訊並在屏幕中打印反饋結果,發送給glbd的通用語法以下: host_address 變量能夠是運行glbd的主機名或者是ip地址,一般是127.0.0.1. port 爲glbd的監聽端口。咱們能夠在啓動glbd的時候指定端口號。 啓動glbd的語法以下 若是該服務器有多個ip地址,則port處須要寫明具體的ip地址和端口號,好比這樣:192.168.0.123:8000 node_list處填寫集羣節點,以逗號隔開。每一個節點能夠經過這樣的方式指定 address:port:weight. 權重是glbd中的一個重要概念,可是它僅僅在經過--top 或者 --single 參數啓動時使用,或者若是所使用的策略(下面描述)考慮節點的權重。經過 --top 選項,使得若是其中至少有一個正在運行,那麼將始終使用具備較高權重的那個節點。若是全部節點權重相同,則該選項無效。使用 --single 選項,那麼僅使用權重最高的節點直到該節點宕機。若是某些服務器在具備低資源的機器上運行,那麼節點的權重就是一個頗有用的功能,而且應該僅用於複製,除非其餘節點崩潰。 glbd支持標準信息選項。好比 --help(打印幫助信息)和--version(輸出版本號)。--verbose能夠在屏幕中打印更多的信息。 列舉一些比較重要的選項: 1 --daemon 使glbd做爲一個daemon運行 2 --control <port > 指定經過哪一個端口來接受nc發出的管理命令 3 --discovery 當有新節點加入集羣時,自動發現並添加。 4 --top和--single 引導glbd根據節點權重來重定位負載。 5 --max_con <number> 設置容許的最大鏈接數以免集羣超過負載。即使不指定該選項,操做系統自己也會限制。 6 --threads <number>指定使用的線程數,默認爲1 7 正常狀況下,glbd經過合併小的數據包來優化網絡。能夠經過--nodelay 選項來關閉該機制。 除非使用--single選項,不然咱們一般須要讓glbd決定使用哪一種策略來指定sql語句執行的目的地。如下是幾種可選的策略。 1 若是不指明其餘策略,默認使用最少鏈接數。它會把每一個鏈接重定向到當前鏈接數最小的節點上。節點的權重也會考慮在內,所以會有負載重的節點比輕的節點接收更多鏈接的狀況出現。 2 --round選項,glbd輪訓集羣節點。當新的鏈接到達時,它會重定向到當前節點,而且指針前進指向下一節點或返回到列表中的第一個節點。 3 --random 每一個鏈接會被隨機重定向到集羣中的節點 4 --source 每一個客戶端會關聯到不一樣的節點,全部來自同一客戶端的鏈接會被重定向到同一臺節點,除非該節點宕機。 glbd使用案例以下: glbd --daemon --control 8765 --thread 4 3306 host1:4567:1 host2:4567:1 host3:4567:1 本例中,daemon將會爲每一個鏈接監聽3306端口(MySQL,MariaDB的標準端口),8765端口用來接收管理命令。咱們有三個權重同樣的主機而且使用了標準策略。glbd使用4個併發線程。 glbd --daemon --single 3306 host1:4567:3 host2:4567:2 host3:4567:1 本例中,glbd沒有指定管理端口,所以不能在運行時修改節點列表。有三個不一樣權重的節點,可是隻有host1會被用來接收sql。若是host1宕機,則有host2 接手,以此類推。 下面咱們使用nc命令來添加一個新節點 echo "host4:4567:1" | nc -q 127.0.0.1 8765 而後是刪除一個節點 echo "host2:4567:-1" | nc -q 127.0.0.1 8765 經過給host2設置-1的權重來從節點列表中刪除一個節點,所以host2不再會被使用。 咱們能夠經過使用nc來獲取glbd的統計數據,好比這樣 總結: 本章咱們討論瞭如何安裝配置和管理MariaDB服務器。 討論了安裝,配置以及啓動單獨的節點來把它們鏈接到一塊兒。學習了使用galera 仲裁器來處理腦裂問題 討論瞭如何監控集羣以及找出性能問題 儘管MariaDB galera cluster和單節點的MariaDB服務器很是相似,但仍舊有不少限制。好比,咱們知道須要避免在galera中使用 query cache或者XA事物 最後,咱們學習了galera load balancer——用以分散節點的負載。 本書中,咱們涵蓋了有關MariaDB優化,管理,安裝等幾個高級主題。如今咱們已經掌握瞭解決在服務器活動期間可能出現的全部常見問題的一些必要知識。好比說實施備份計劃或者配置複製環境或者集羣。固然,這些知識遠遠不夠。讀者自身須要理論聯繫實際,多操做。這多是最難完成的部分,可是經過這本書和在線文檔,咱們能夠不時地找到咱們所須要的信息。
pdfhtml