1.MySQL Server 系統架構
? ??邏輯模塊組成:MySQL 可以看成是二層架構,第一層我們通常叫做SQL Layer,在MySQL 數據庫系統處理底層數據之前的所有工作都是在這一層完成的,包括權限判斷,sql 解析,執行計劃優化,query cache 的處理等等;第二層就是存儲引擎層,我們通常叫做StorageEngine Layer,也就是底層數據存取操作實現部分,由多種存儲引擎共同組成。
????SQL-Layer組成:
????1、初始化模塊:對整個系統做各種各樣的初始化操作,比如各種buffer,cache 結構的初始化和內存空間的申請,各種系統變量的初始化設定,各種存儲引擎的初始化設置
? ??2、核心API:提供一些需要非常高效的底層操作功能的優化實現,包括各種底層數據結構的實現,特殊算法的實現,字符串處理,數字處理等,小文件I/O,格式化輸出,以及最重要的內存管理部分。
? ? 3、網絡交互模塊:,實現底層網絡數據的接收與發送
? ??4、Client & Server 交互協議模塊:實現了客戶端與MySQL 交互過程中的所有協議。當然這些協議都是建立在現有的OS 和網絡協議之上的,如TCP/IP 以及Unix Socket
? ??5、用戶模塊:主要包括用戶的登錄連接權限控制和用戶的授權管理
? ??6、訪問控制模塊:控制用戶對數據的訪問,將用戶模塊和訪問控制模塊兩者結合起來,組成了MySQL 整個數據庫系統的權限安全管理的功能。
? ??7、連接管理、連接線程和線程管理:連接線程的主要工作就是負責MySQL Server 與客戶端的通信,接受客戶端的命令請求,傳遞Server 端的結果信息等。線程管理模塊則負責管理維護這些連接線程。包括線程的創建,線程的cache 等。
? ? 8:Query 解析和轉發模塊:主要工作就是將query 語句進行語義和語法的分析,然后按照不同的操作類型進行分類,然后做出針對性的轉發。
? ??9、Query Cache 模塊:主要功能是將客戶端提交給MySQL 的Select 類query 請求的返回結果集cache 到內存中
? ??10、Query 優化器模塊:優化客戶端請求的query
? ??11、表變更管理模塊:表變更管理模塊主要是負責完成一些DML 和DDL 的query,如:update,delte,insert,create table,alter table 等語句的處理
? ??12、表維護模塊:表的狀態檢查,錯誤修復,以及優化和分析等工作都是表維護模塊需要做的事情。
? ??13、系統狀態管理模塊:系統狀態管理模塊負責在客戶端請求系統狀態的時候,將各種狀態數據返回給用戶
? ??14、表管理器:主要內容是各個表的結構信息。此外它還維護table 級別的鎖管
? ??15、日志記錄模塊日志記錄模塊主要負責整個系統級別的邏輯層的日志的記錄,包括error log,binarylog,slow query log 等。
? ??16、復制模塊:復制模塊又可分為Master 模塊和Slave 模塊兩部分, Master 模塊主要負責在Replication 環境中讀取Master 端的binary 日志,以及與Slave 端的I/O 線程交互等工作。Slave 模塊比Master 模塊所要做的事情稍多一些,在系統中主要體現在兩個線程上面。一個是負責從Master 請求和接受binary 日志,并寫入本地relay log 中的I/O 線程。另外一個是負責從relay log 中讀取相關日志事件,然后解析成可以在Slave 端正確執行并得到和Master 端完全相同的結果的命令并再交給Slave 執行的SQL 線程。
? ??17、存儲引擎接口模塊:實現可插拔存儲引擎
2.日志文件
? ??1、錯誤日志:Error Log???????
? ??????錯誤日志的默認存放位置在數據目錄下,以hostname.err 命名
? ??????log-error[=file_name],修改其存放目錄和文件名。
?????2、二進制日志:Binary Log & Binary Log Index
? ??????log-bin[=on|off]:打開/關閉記錄功能
? ??????max_binlog_size:設置binlog 的最大存儲上限,當日志達到該上限時,MySQL 會重新創建一個日志開始繼續記錄?
????3、查詢日志:query log
? ??????????general_log[=on|off]:打開/關閉查詢日志
????????????general_log_file[=filename]: 查詢日志文件名
? ? 4、慢查詢日志:slow query log
? ??????????slow_query_log[=on|off]:打開/關閉慢查詢日志
? ??????????long_query_time[=long]:超過多少秒的查詢就寫入日志
? ? 5、Innodb 的在線redo 日志:innodb redo log
? ??????????Innodb 是一個事務安全的存儲引擎,其事務安全性主要就是通過在線redo 日志和記錄在表空間中的undo 信息來保證的。redo 日志中記錄了Innodb 所做的所有物理變更和事務信息,可以通過innodb_log_group_home_dir 來更改設置日志的存放位置,通過innodb_log_files_in_group 設置日志的數量。
3.數據文件
? ??1、“.MYD”文件:MyISAM 存儲引擎專用,存放MyISAM 表的數據。每一MyISAM 表都會有一個“.MYD”文件與之對應。
? ? 2、“.MYI”文件:專屬于MyISAM 存儲引擎,主要存放MyISAM 表的索引相關信息
? ? 3、“.ibd”文件和ibdata 文件:獨享表空間存儲方式使用“.ibd”文件來存放數據,且每個表一個“.ibd”文件,文件存放在和MyISAM 數據相同的位置。如果選用共享存儲表空間來存放數據,則會使用ibdata 文件來存放,所有表共同使用一個(或者多個,可自行配置)ibdata 文件。ibdata 文件可以通過innodb_data_home_dir 和innodb_data_file_path兩個參數共同配置組成
? ??????innodb_data_file_path默認值是ibdata1:12M:autoextend,ibdata共享表文件,12M設置表空間大小,autoextend自動擴展。
4.Replication相關文件
? ??1、master.info 文件:master.info 文件存在于Slave 端的數據目錄下,里面存放了該Slave 的Master 端的相關信息,包括Master 的主機地址,連接用戶,連接密碼,連接端口,當前日志位置,已經讀取到的日志位置等信息。
? ??2、relay log 和relay log index:mysql-relay-bin.xxxxxn 文件用于存放Slave 端的I/O 線程從Master 端所讀取到的Binary Log 信息,然后由Slave 端的SQL 線程從該relay log 中讀取并解析相應的日志信息,轉化成Master 所執行的SQL 語句,然后在Slave 端應用。
? ?3、 relay-log.info 文件:類似于master.info,它存放通過Slave 的I/O 線程寫入到本地的relay log 的相關信息
5.其他文件
? ??1、system config file:MySQL 的系統配置文件一般都是“my.cnf”,Unix/Linux 下默認存放在"/etc"目錄下,Windows 環境一般存放在“c:/windows”目錄下面。
? ??2、pid file:mysqld 應用程序在Unix/Linux 環境下的一個進程文件,和許多其他Unix/Linux 服務端程序一樣,存放著自己的進程id。
? ? 3、socket file:用戶在Unix/Linux 環境下客戶端連接可以不通過TCP/IP 網絡而直接使用Unix Socket 來連接MySQL。
6.mysql自帶工具
????mysqladmin:與MySQL 管理相關的各種功能
? ??????Usage: mysqladmin [OPTIONS] command command ...
? ??????mysqladmin -uroot -p123 -hlocalhost ping????//檢測MySQL Server 是否還能正常提供服務
? ? ? ? >mysqld is alive
? ??????mysqladmin -uroot -p123 -hlocalhost status? ?// 獲取當前MySQL Server 的幾個基本的狀態值
? ? ? ? >Uptime: 20960 Threads: 1 Questions: 75 Slow queries: 0 Opens: 15 Flush
? ? ? ? >tables: 1 Open tables: 9 Queries per second avg: 0.3
? ??????mysqladmin -uroot -p123 -hlocalhost processlist? ? //獲取當前數據庫的連接線程信息
? ??????此外,還可以通過mysqladmin 來start slave 和stop slave,kill 某個連接到MySQL Server 的線程等等。
? ??mysqldump? ?:將MySQL Server中的數據以SQL 語句的形式從數據庫中dump 成文本文件。這
個功能實際上是調用了MySQL 中的“select * into OUTFILE from ...”語句而實現
? ?????Usage: mysqldump [OPTIONS] database [tables].
????????OR mysqldump [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]
????????OR mysqldump [OPTIONS] --all-databases [OPTIONS]
? ??????可以通過“-d,--no-data”僅僅生成結構創建的語句,每次執行mysqldump 程序的時候都通過盡量做到“--defaultcharacter-set=name”顯式指定字符集內容
? ??mysqlimport :mysqlimport 程序是一個將以特定格式存放的文本數據(如通過“select * into OUTFILE from ...”所生成的數據文件)導入到指定的MySQL Server 中的工具程序
? ??Usage: mysqlimport [OPTIONS] database textfile ...
? ??mysqlbinlog:通過mysqlbinlog,我們可以解析出binlog 中指定時間段或者指定日志起始和結束位置的內容解析成SQL 語句,并導出到指定的文件中,在解析過程中,還可以通過指定數據庫名稱來過濾輸出內容。
? ??????Usage: mysqlbinlog [OPTIONS] log-files
? ? ? ??
????mysqlcheck
? ??????Usage: mysqlcheck [OPTIONS] database [tables]
????????OR mysqlcheck [OPTIONS] --databases DB1 [DB2 DB3...]
????????OR mysqlcheck [OPTIONS] --all-databases
? ??????mysqlcheck 工具程序可以檢查(-c),修復(-r),分析( -a)和優化????(-o)MySQL Server 中的表
????myisamchk
? ??????Usage: myisamchk [OPTIONS] tables[.MYI]
? ??????功能有點類似“mysqlcheck -c/-r”,對檢查和修復MyISAM 存儲引擎的表,但只能對MyISAM 存儲引擎的索引文件有效
????myisampack
? ??Usage: myisampack [OPTIONS] filename ...
? ??對MyISAM 表進行壓縮處理,以縮減占用存儲空間,一般主要用在歸檔備份的場景下,而且壓縮后的MyISAM 表會變成只讀,不能進行任何修改操作。
? ??mysqlhotcopy
? ??Usage: mysqlhotcopy db_name[./table_regex/] [new_db_name | directory]
? ??僅能在Unix/Linux 環境下使用。他的主要功能就是對MySQL 中的MyISAM 存儲引擎的表進行在線備份操作,其備份操作實際上就是通過對數據庫中的表進行加鎖,然后復制其結構,數據和索引文件來完成備份操作
7.數據引擎
? ??MySQL 的插件式存儲引擎主要包括MyISAM,Innodb,NDB Cluster,Maria,Falcon,Memory,Archive,Merge,Federated 等
? ??MyISAM 存儲引擎
? ? 特點:1、表的行結構緊湊,浪費空間少,因此比較適合數據倉庫系統
????????????????2、因為沒有redo、沒有undo,因此進行insert的時候,速度相對較快
? ??MyISAM 支持以下三種類型的索引:1、B-Tree 索引 2、R-Tree 索引?3、Full-text 索引
? ??
????Innodb 存儲引擎
? ? 特點:1、支持事務安裝????2、數據多版本讀取 3、使用行級鎖????4、實現外鍵
? ??Innodb 的物理結構分為兩大部分:
? ??1、數據文件(表數據和索引數據)
? ??????在Innodb 中,存在了表空間(tablespace)這樣一個概念,Innodb 的表空間分為兩種形式。一種是共享表空間,也就是所有表和索引數據被存放在同一個表空間(一個或多個數據文件idata)中,通過innodb_data_file_path 來指定,增加數據文件需要停機重啟,Innodb 的undo 信息和其他一些元數據信息都是存放在共享表空間里面的。另外一種是獨享表空間,也就是每個表的數據和索引被存放在一個單獨的.ibd 文件中。
? ??????共享表空間增加數據文件的操作比較簡單, 只需要在innodb_data_file_path 參數后面按照標準格式設置好文件路徑和相關屬性即可,不過這里有一點需要注意的,就是Innodb 在創建新數據文件的時候是不會創建目錄的,如果指定目錄不存在,則會報錯并無法啟動
? ??2、日志文件
? ??????由于Innodb 是事務安全的存儲引擎,所以系統Crash 對他來說并不能造成非常嚴重的損失,由于有redo 日志的存在,有checkpoint 機制的保護,Innodb 完全可以通過redo 日志將數據庫Crash 時刻已經完成但還沒有來得及將數據寫入磁盤的事務恢復,也能夠將所有部分完成并已經寫入磁盤的未完成事務回滾并將數據還原。
? ??????Innodb 的所有參數基本上都帶有前綴“innodb_”。
????NDB Cluster存儲引擎
? ??????NDB 存儲引擎也叫NDB Cluster 存儲引擎,主要用于MySQL Cluster 分布式集群環境,Cluster 是MySQL 從5.0 版本才開始提供的新功能。
? ??????一般來說,一個Mysql Cluster 的環境主要由以下三部分組成:
? ??????a) 負責管理各個節點的Manage 節點主機:于管理節點上保存在整個Cluster 環境的配置,同時擔任了集群中各節點的基本溝通工作,所以他必須是最先被啟動的節點。
? ??????b) SQL 層的SQL 服務器節點(后面簡稱為SQL 節點),也就是我們常說的Mysql Server:主要負責實現一個數據庫在存儲層之上的所有事情,比如連接管理,query 優化和響應,cache 管理等等,只有存儲層的工作交給了NDB 數據節點去處理了。SQL 層各Mysql 服務器的啟動與普通的Mysql 啟動有一定的區別,必須要添加ndbcluster 項,可以添加在my.cnf 配置文件中,也可以通過啟動命令行來指定。
? ??????c) Storage 層的NDB 數據節點,也就是上面說的NDB Cluster:NDB 節點主要是實現底層數據存儲的功能,保存Cluster 的數據。每一個NDB 節點保存完整數據的一部分。
????其他存儲引擎
? ??????Merge存儲引擎:MERGE 存儲引擎可以簡單的理解為其功能就是實現了對結構相同的MyISAM 表,通過一些特殊的包裝對外提供一個單一的訪問入口,以達到減小應用的復雜度的目的
? ??????Memory存儲引擎:將數據存儲在內存中的存儲引擎。MySQL Crash 或者主機Crash 之后,Memory 的表就只剩下一個結構了。Memory 表支持索引,并且同時支持Hash 和B-Tree 兩種格式的索引。
? ? ? ? 另外還有BDB 存儲引擎、FEDERATED存儲引擎、ARCHIVE存儲引擎、BLACKHOLE存儲引擎、CSV存儲引擎,不一一列舉。
8.權限系統
? ??MySQL 的權限系統在實現上比較簡單,相關權限信息主要存儲在幾個被稱為granttables 的系統表中,即: mysql.User,mysql.db,mysql.Host,mysql.table_priv 和mysql.column_priv。
? ?mysql 在啟動的時候,就會將所有的權限信息都Load 到內存中保存在幾個特定的結構中,所以才有我們每次手工修改了權限相關的表之后,都需要執行“FLUSH PRIVILEGES”命令重新加載MySQL的權限信息。當然,如果我們通過GRANT,REVOKE 或者DROP USER 命令來修改相關權限,則不需要手工執行FLUSH PRIVILEGES 命令,因為通過GRANT,REVOKE 或者DROP USER 命令所做的權限修改在修改系統表的同時也會更新內存結構中的權限信息。
? ??權限授予與去除:要為某個用戶授權,可以使用GRANT 命令,要去除某個用戶已有的權限則使用REVOKE命令。當給某個用戶授權的時候,不僅需要指定用戶名,同時還要指定來訪主機。
? ??查看某個用戶目前擁有的權限可以通過“SHOW GRANTS FOR 'username'@'hostname'”和查詢mysql.user里面的權限信息。
? ???創建用戶:CREATE USER 'username'@'host' IDENTIFIED BY 'password';
? ???授權:GRANT privileges ON databasename.tablename TO 'username'@'host'
????????????用戶的操作權限,如SELECT,INSERT,UPDATE等,如果要授予所的權限則使用ALL。 如果想讓該用戶可以授權,用以下命令:
????????????????GRANT privileges ON databasename.tablename TO 'username'@'host' WITH GRANT OPTION;
? ??設置與更改用戶密碼:SET PASSWORD FOR 'username'@'host' =PASSWORD('newpassword');
? ??撤銷用戶權限::REVOKE privilege ON databasename.tablename FROM 'username'@'host';
? ??刪除用戶:DROP USER 'username'@'host';
9.數據庫備份
? ??mysqldump邏輯備份
????”--single-transaction”選項,可以達到備份數據的一致性和完整性
? ??“--lock-tables”和“--lock-all-tables”,讓數據庫在備份過程中僅提供數據的查詢服務,鎖定寫入的服務,來使數據暫時處于一個一致的不會被修改的狀態
? ??“--master-data[=value]”會將當前MySQL 使用到binlog 日志的名稱和位置記錄到dump 文件中。這個選項在實施slave 的在線搭建的時候是非常有用的,即使不是進行在線搭建slave,也可以在某些情況下做恢復的過程中通過備份的binlog 做進一步恢復操作。
? ? "--no-data”僅僅dump 數據庫結構創建腳本?
? ? mysqldump邏輯恢復?
? ??可以通過在mysql 中執行“source /path/backup.sql”或者“\. /path/backup.sql”來進行恢復。或在命令行使用mysql -uusername -p < backup.sql
? ??數據庫物理課備份
? ? ?數據庫的物理備份就是對數據庫的物理對象所做的備份。
? ? MyISAM物理備份需要備份的內容有:.frm”文件,存儲表數據的“.MYD”文件,以及存儲索引數據的“.MYI”文件
? ??Innodb 存儲引擎“innodb_data_home_dir”和“innodb_data_file_path”參數所設定的所有數據文件,“datadir”中相應數據庫目錄下的所有Innodb 存儲引擎表的“.frm”文件“.idb”文件,redo文件
? ??NDB Cluster 存儲引擎1、元數據(Metadata)2、表數據(Table Records)3、事務日志數據(Transaction Log):
? ??我們也可以通過登錄數據庫中手工加鎖,然后再通過操作系統的命令來復制相關文件執行熱物理備份,且在完成文件copy 之前,不能退出加鎖的session(因為退出會自動解鎖),執行FLUSH TABLES WITH READ LOCK;
10.MyISAM 鎖優化
? ??MyISAM 表鎖優化建議優化MyISAM 存儲引擎鎖定問題的時候,最關鍵的就是如何讓其提高并發度。由于鎖定級別是不可能改變的了,所以我們首先需要盡可能讓鎖定的時間變短,然后就是讓可能并發進行的操作盡可能的并發。
? ??1、縮短鎖定時間
? ??????a) 盡兩減少大的復雜Query,將復雜Query 分拆成幾個小的Query 分布進行;
? ??????b) 盡可能的建立足夠高效的索引,讓數據檢索更迅速;
? ??????c) 盡量讓MyISAM 存儲引擎的表只存放必要的信息,控制字段類型;
? ??????d) 利用合適的機會優化MyISAM 表數據文件;
????2、分離能并行的操作
? ? ? ? 配置是Concurrent Insert(并發插入),MyISAM 存儲引擎有一個控制是否打開Concurrent Insert 功能的參數選項:concurrent_insert,可以設置為0,1 或者2。三個值的具體說明如下:
? ??????a) set global concurrent_insert=2(always)2,無論MyISAM 存儲引擎的表數據文件的中間部分是否存在因為刪除數據而留下的空閑空間,都允許在數據文件尾部進行Concurrent Insert;
? ??????b)?set global? concurrent_insert=1(auto)當MyISAM 存儲引擎表數據文件中間不存在空閑空間的時候,可以從文件尾部進行Concurrent Insert;
? ??????c) set global??concurrent_insert=0(never),無論MyISAM 存儲引擎的表數據文件的中間部分是否存在因為刪除數據而留下的空閑空間,都不允許Concurrent Insert。
? ? 3、合理利用讀寫優先級
? ??????如果我們的系統是一個以讀為主,而且要優先保證查詢性能的話,我們可以通過設置系統參數選項low_priority_updates=1,如果我們的系統需要有限保證數據寫入的性能的話,則可以不用設置low_priority_updates參數
11.innodb鎖優化
? ??Innodb 存儲引擎由于實現了行級鎖定,雖然在鎖定機制的實現方面所帶來的性能損耗可能比表級鎖定會要更高一些,但是在整體并發處理能力方面要遠遠優于MyISAM 的表級鎖定的
? ??a) 盡可能讓所有的數據檢索都通過索引來完成,從而避免Innodb 因為無法通過索引鍵加鎖而升級為表級鎖定;
? ??b) 合理設計索引,讓Innodb 在索引鍵上面加鎖的時候盡可能準確,盡可能的縮小鎖定范圍,避免造成不必要的鎖定而影響其他Query 的執行;
? ??c) 盡可能減少基于范圍的數據檢索過濾條件,避免因為間隙鎖帶來的負面影響而鎖定了不該鎖定的記錄;
? ??d) 盡量控制事務的大小,減少鎖定的資源量和鎖定時間長度;
? ??e) 在業務環境允許的情況下,盡量使用較低級別的事務隔離,以減少MySQL 因為實現事務隔離級別所帶來的附加成本;
? ??減少死鎖產生概率建議:
? ??a) 類似業務模塊中,盡可能按照相同的訪問順序來訪問,防止產生死鎖;
? ??b) 在同一個事務中,盡可能做到一次鎖定所需要的所有資源,減少死鎖產生概率;
? ??c) 對于非常容易產生死鎖的業務部分,可以嘗試使用升級鎖定顆粒度,通過表級鎖定來減少死鎖產生的概率;
? ??系統鎖定爭用情況查詢:show status like 'table%';
? ??Table_locks_immediate:產生表級鎖定的次數;
? ??Table_locks_waited:出現表級鎖定爭用而發生等待的次數,如果Table_locks_waited 狀態值比較高,那么說明系統中表級鎖定爭用現象比較嚴重
? ? innodb鎖定爭用情況查詢:show status like 'innodb_row_lock%';
? ??Innodb_row_lock_current_waits:當前正在等待鎖定的數量;
????Innodb_row_lock_time:從系統啟動到現在鎖定總時間長度;
????Innodb_row_lock_time_avg:每次等待所花平均時間;
????Innodb_row_lock_time_max:從系統啟動到現在等待最常的一次所花的時間;
????Innodb_row_lock_waits:系統啟動后到現在總共等待的次數;
12.Query 的優化?
? ??Query 語句優化基本思路和原則
? ??1. 優化更需要優化的Query;
? ??????一般來說,高并發低消耗(相對)的Query 對整個系統的影響遠比低并發高消耗的Query 大(io次數高cpu消耗大)。
????2. 定位優化對象的性能瓶頸;
? ??????PROFILING 功能很清楚的找出一個Query 的瓶頸所在。
? ??????1、 開啟 profiling 參數set profiling=1;????????? 2、 執行 Query
? ? ? ? 3、show profiles;獲取系統中保存的所有 Query 的 profile 概要信息
? ? ? ? 4、 針對單個 Query 獲取詳細的 profile 信息show PROFILE cpu ,block io for query 116
????3. 從Explain 入手;
? ? ? ?Explain 功能中給我們展示的各種信息的解釋:
? ??????ID:Query Optimizer 所選定的執行計劃中查詢的序列號;
? ??????Select_type:所使用的查詢類型,主要有以下這幾種查詢類型
????????????◇ DEPENDENT SUBQUERY:子查詢中內層的第一個SELECT,依賴于外部查詢的結果集;◇ DEPENDENT UNION:子查詢中的UNION,且為UNION 中從第二個SELECT 開始的后面所有SELECT,同樣依賴于外部查詢的結果集;◇ PRIMARY:子查詢中的最外層查詢,注意并不是主鍵查詢;◇ SIMPLE:除子查詢或者UNION 之外的其他查詢;◇ SUBQUERY:子查詢內層查詢的第一個SELECT,結果不依賴于外部查詢結果集;◇ UNCACHEABLE SUBQUERY:結果集無法緩存的子查詢;◇ UNION:UNION 語句中第二個SELECT 開始的后面所有SELECT,第一個SELECT 為PRIMARY◇ UNION RESULT:UNION 中的合并結果;
? ??????Table:顯示這一步所訪問的數據庫中的表的名稱;
? ??????Type:告訴我們對all:全表掃描表所使用的訪問方式
????????????◇ const:讀常量,且最多只會有一條記錄匹配,由于是常量,所以實際上只需要讀一次;◇ eq_ref:最多只會有一條匹配結果,一般是通過主鍵或者唯一鍵索引來訪問;◇ fulltext:◇ index:全索引掃描;◇ index_merge:查詢中同時使用兩個(或更多)索引,然后對索引結果進行merge 之后再讀取表數據;◇ index_subquery:子查詢中的返回結果字段組合是一個索引(或索引組合),但不是一個主鍵或者唯一索引;◇ rang:索引范圍掃描;◇ ref:Join 語句中被驅動表索引引用查詢;◇ ref_or_null:與ref 的唯一區別就是在使用索引引用查詢之外再增加一個空值的查詢;◇ system:系統表,表中只有一行數據;◇ unique_subquery:子查詢中的返回結果字段組合是主鍵或者唯一約束
????? ??Possible_keys:該查詢可以利用的索引. 如果沒有任何索引可以使用,就會顯示成null
? ??????Key:MySQL Query Optimizer 從possible_keys 中所選擇使用的索引;
? ??????Key_len:被選中使用索引的索引鍵長度;
? ??????Ref:列出是通過常量(const),還是某個表的某個字段(如果是join)來過濾(通過key)的;
? ? ? ? Rows:MySQL Query Optimizer 通過系統收集到的統計信息估算出來的結果集記錄條數;
? ??????Extra:查詢中每一步實現的額外細節信息? ? ? ? ? ?
?????????????◇ Distinct:查找distinct 值,所以當mysql 找到了第一條匹配的結果后,將停止該值的查詢而轉為后面其他值的查詢;◇ Full scan on NULL key:子查詢中的一種優化方式,主要在遇到無法通過索引訪問null值的使用使用;◇ Impossible WHERE noticed after reading const tables:MySQL Query Optimizer 通過收集到的統計信息判斷出不可能存在結果;◇ No tables:Query 語句中使用FROM DUAL 或者不包含任何FROM 子句;◇ Not exists:在某些左連接中MySQL Query Optimizer 所通過改變原有Query 的組成而使用的優化方法,可以部分減少數據訪問次數;◇ Range checked for each record (index map: N):通過MySQL 官方手冊的描述,當MySQL Query Optimizer 沒有發現好的可以使用的索引的時候,如果發現如果來自前面的表的列值已知,可能部分索引可以使用。對前面的表的每個行組合,MySQL 檢查是否可以使用range 或index_merge 訪問方法來索取行。◇ Select tables optimized away:當我們使用某些聚合函數來訪問存在索引的某個字段的時候,MySQL Query Optimizer 會通過索引而直接一次定位到所需的數據行完成整個查詢。當然,前提是在Query 中不能有GROUP BY 操作。如使用MIN()或者MAX()的時候;◇ Using filesort:當我們的Query 中包含ORDER BY 操作,而且無法利用索引完成排序操作的時候,MySQL Query Optimizer 不得不選擇相應的排序算法來實現。◇ Using index:所需要的數據只需要在Index 即可全部獲得而不需要再到表中取數據;◇ Using index for group-by:數據訪問和Using index 一樣,所需數據只需要讀取索引即可,而當Query 中使用了GROUP BY 或者DISTINCT 子句的時候,如果分組字段也在索引中,Extra 中的信息就會是Using index for group-by;◇ Using temporary:當MySQL 在某些操作中必須使用臨時表的時候,在Extra 信息中就會出現Using temporary 。主要常見于GROUP BY 和ORDER BY 等操作中。◇ Using where:如果我們不是讀取表的所有數據,或者不是僅僅通過索引就可以獲取所有需要的數據,則會出現Using where 信息;◇ Using where with pushed condition:這是一個僅僅在NDBCluster 存儲引擎中才會出現的信息,而且還需要通過打開Condition Pushdown 優化功能才可能會被使用。控制參數為engine_condition_pushdown 。
? ? ? ?a) 永遠用小結果集驅動大的結果集。因為在MySQL 中的Join,只有Nested Loop 一種Join 方式,也就是MySQL 的Join 都是通過嵌套循環來實現的。
? ? ? b)只取出自己需要的Columns。對于任何Query,返回的數據都是需要通過網絡數據包傳回給客戶端,如果取出的Column 越多,需要傳輸的數據量自然會越大。如果是需要排序的Query 來說,影響就更大了。在MySQL 中存在兩種排序算法,一種是在MySQL4.1 之前的老算法,實現方式是先將需要排序的字段和可以直接定位到相關行數據的指針信息取出,然后在我們所設定的排序區(通過參數sort_buffer_size 設定)中進行排序,完成排序之后再次通過行指針信息取出所需要的Columns,也就是說這種算法需要訪問兩次數據。第二種排序算法是從MySQL4.1 版本開始使用的改進算法,一次性將所需要的Columns 全部取出,在排序區中進行排序后直接將數據返回給請求客戶端。改行算法只需要訪問一次數據,減少了大量的隨機IO,極大的提高了帶有排序的Query 語句的效率。但是,這種改進后的排序算法需要一次性取出并緩存的數據比第一種算法要多很多,如果我們將并不需要的Columns 也取出來,就會極大的浪費排序過程所需要的內存。在MySQL4.1 之后的版本中,我們可以通過設置max_length_for_sort_data 參數大小來控制MySQL 選擇第一種排序算法還是第二種排序算法。當所取出的Columns 的單條記錄總大小max_length_for_sort_data 設置的大小的時候,MySQL 就會選擇使用第一種排序算法,反之,則會選擇第二種優化后的算法。為了盡可能提高排序性能,我們自然是更希望使用第二種排序算法,所以在Query 中僅僅取出我們所需要的Columns 是非常有必要的。
? ? c)僅僅使用最有效的過濾條件。因為不同的索引鍵長度,如果多個索引鍵都能與表一一對應,那么應該只使用鍵長度較短的索引作為過濾條件。
? ? d)盡可能避免復雜的Join 和子查詢。Query 語句所涉及到的越復雜的Join 語句,所需要鎖定的資源也就越多,所表越多,所需要鎖定的資源就越多。也就是說,阻塞的其他線程也就越多。如果我們將比較復雜的Query 語句分拆成多個較為簡單的Query 語句分步執行,每次鎖定的資源也就會少很多,所阻塞的其他線程也要少一些。(犧牲響應時間提高整體處理能力)
? ? 4.合理利用索引
? ??????如何判定是否需要創建索引?
? ??????????◆ 較頻繁的作為查詢條件的字段應該創建索引;
? ??????????◆ 唯一性太差的字段不適合單獨創建索引,即使頻繁作為查詢條件;
? ??????????◆ 更新非常頻繁的字段不適合創建索引;
? ??????????◆ 不會出現在WHERE 子句中的字段不該創建索引;
? ? ????使用組合索引
? ? ? ? ? ?只要不是其中如果某個過濾字段在大多數場景下都能過濾出90%以上的數據,而且其他的過濾字段會存在頻繁的更新,都建議創建組合索引。因為當我們的并發量較高的時候,即使我們為每個Query 節省很少的IO 消耗,但因為執行量非常大,所節省的資源總量仍然是非常可觀的。
? ?????強制使用索引:
? ? ? ? 在有些情況下,可能是由于我們的系統統計信息的不夠準確完整,也可能是MySQL Query Optimizer 自身功能的缺陷,會造成他并沒有選擇一個真正最優的索引而選擇了其他查詢效率較低的索引。這時可以使用 FORCE INDEX(index_name)強制使用索引。
? ?5. MySQL 中索引的限制
? ??????1. MyISAM 存儲引擎索引鍵長度總和不能超過1000 字節;
????????2. BLOB 和TEXT 類型的列只能創建前綴索引;
????????3. MySQL 目前不支持函數索引;
????????4. 使用不等于(!= 或者<>)的時候MySQL 無法使用索引;
????????5. 過濾字段使用了函數運算后(如abs(column)),MySQL 無法使用索引;
????????6. Join 語句中Join 條件字段類型不一致的時候MySQL 無法使用索引;
????????7. 使用LIKE 操作的時候如果條件以通配符開始( '%abc...')MySQL 無法使用索引;
????????8. 使用非等值查詢的時候MySQL 無法使用Hash 索引;
13.Join 的實現原理及優化思路
? ??在MySQL 中只有Nested Loop Join算法,實際上就是通過驅動表的結果集作為循環基礎數據,然后一條一條的通過該結果集中的數據作為過濾條件到下一個表中查詢數據,然后合并結果。
? ? 當join類型為all,index,rang,index_merge時,會使用Join Buffer(緩存)結果集,可以通過join_buffer_size 參數設置Join buffer的大小
? ??Join 語句的優化
? ??????1. 盡可能減少Join 語句中的Nested Loop 的循環總次數。永遠用小結果集驅動大的結果集
? ??????2. 優先優化Nested Loop 的內層循環。因為內層循環是循環中執行次數最多的
? ? ? ? 3.當無法保證被驅動表的Join 條件字段被索引且內存資源充足的前提下,不要太吝惜JoinBuffer 的設置
? ? ? ? 4.保證Join 語句中被驅動表上Join 條件字段已經被索引
14.ORDER BY的實現與優化
? ??ORDER BY 的實現 。在MySQL 中,ORDER BY 的實現有如下兩種類型:
? ? ? ? a)一種是通過有序索引而直接取得有序的數據
? ??????????利用索引實現數據排序的方法是MySQL 中實現結果集排序的最佳做法,可以完全避免因為排序計算所帶來的資源消耗。
? ? ? ? b)通過MySQL 的排序算法將存儲引擎中返回的數據進行排序
? ? ? ? ? ?排序有兩種實現:1、取出滿足過濾條件的用于排序條件的字段以及可以直接定位到行數據的行指針信息,在SortBuffer 中進行實際的排序操作,然后利用排好序之后的數據根據行指針信息返回表中取得客戶端請求的其他字段的數據????2、根據過濾條件一次取出排序字段以及客戶端請求的所有其他字段的數據,并將不需要排序的字段存放在一塊內存區域中,然后在Sort Buffer 中將排序字段和行指針信息進行排序,最后再利用排序后的行指針與存放在內存區域中和其他字段一起的行指針信息進行匹配合并結果集
? ??ORDER BY 的優化:
? ? ? ? a)盡可能根據索引排序
? ? ? ? b)當我們無法避免排序操作的時候,可以配置一下參數進行優化:
? ? ? ? ? ? 1.加大max_length_for_sort_data 參數的設置
? ??????????????????在MySQL 中,決定使用第一種老式的排序算法還是新的改進算法的依據是通過參數max_length_for_sort_data 來決定的。當我們所有返回字段的最大長度小于這個參數值的時候,MySQL 就會選擇改進后的排序算法,反之,則選擇老式的算法(需多訪問一次數據庫)
? ? ? ? ? ? 2..去掉不必要的返回字段
? ??????????3. 增大sort_buffer_size 參數設置
? ??????????????????讓MySQL可以盡量減少在排序過程中對需要排序的數據進行分段,因為這樣會造成MySQL 不得不使用臨時表來進行交換排序。
15.GROUP BY 的實現與優化
? ? GROUP BY 實際上也同樣需要進行排序操作,而且與ORDER BY 相比,GROUP BY 主要只是多了排序之后的分組操作。
? ??GROUP BY 的實現有三種:
? ? ? ? ? ? a)使用松散(Loose)(效率高)索引掃描實現GROUP BY。實際上就是當MySQL 完全利用索引掃描來實現GROUP BY 的時候,并不需要掃描所有滿足條件的索引鍵即可完成操作得出結果。在執行計劃的Extra 信息中有信息顯示“Using index for group-by”,實際上這就是告訴我們,MySQL Query Optimizer 通過使用松散索引掃描來實現了我們所需要的GROUP BY 操作。 要利用到松散索引掃描實現GROUP BY,需要至少滿足以下幾個條件:1、GROUP BY 條件字段必須在同一個索引中最前面的連續位置;2、在使用GROUP BY 的同時,只能使用MAX 和MIN 這兩個聚合函數;3、如果引用到了該索引中GROUP BY 條件之外的字段條件的時候,必須以常量形式存在。
? ? ? ????? b)使用緊湊(Tight)索引掃描實現GROUP BY。緊湊索引掃描實現GROUP BY 和松散索引掃描的區別主要在于他需要在掃描索引的時候,讀取所有滿足條件的索引鍵,然后再根據讀取的數據來完成GROUP BY 操作得到相應結果。執行計劃的Extra 信息中顯示“Using where; Using index”
? ? ? ? ? ?c)使用臨時表實現GROUP BY。當MySQL QueryOptimizer 無法找到合適的索引可以利用的時候,就不得不先讀取需要的數據,然后通過臨時表來完成GROUP BY 操作。執行計劃的Extra 信息中顯示“Using where; Using index; Using temporary; Using filesort”
? ??針對GROUP BY有兩種優化思路:
? ??????1. 盡可能讓MySQL 可以利用索引來完成GROUP BY 操作
? ??????2. 當無法使用索引完成GROUP BY 的時候,由于要使用到臨時表且需要filesort,所以我們必須要有足夠的sort_buffer_size。盡量不要進行大結果集的GROUP BY 操作,因為如果超出系統設置的臨時表大小的時候會出現將臨時表數據copy 到磁盤上面再進行操作,這時候的排序分組操作性能將是成數量級的下降;
16.DISTINCT 的實現與優化
? ? ? ?DISTINCT 實際上和GROUP BY 的操作非常相似,只不過是在GROUP BY 之后的每組中只取出一條記錄而已。但是,和GROUP BY 有一點差別的是,DISTINCT 并不需要進行排序。也就是說,在僅僅只是DISTINCT 操作的Query 如果無法僅僅利用索引完成操作的時候,MySQL 會利用臨時表來做一次數據的“緩存”,但是不會對臨時表中的數據進行filesort 操作。
16.高效的模型設計
? ? 1、適度冗余- 讓Query 盡量減少Join
? ? 2、大字段垂直分拆
? ? 3、大表水平分拆
? ? 4、統計表- 準實時優化
17.合適的數據類型
? ??1. 通過選用更“小”的數據類型減少存儲空間,使查詢相同數據需要的IO 資源降低;
? ??2. 通過合適的數據類型加速數據的比較;
????????對于數字類型,這里分別列出了整數類型和小數類型,也就是浮點數類型。實際上,還有一類通過二進制格式以字符串來存放的數字類型如DECIMAL(DEC)[(M[,D])],NUMERIC[(M[,D])],由于其存放長度主要通過其定義時候的的M 所決定,M 定義為多大,則實際存放就有多長。M 代表整個位數長度,而D 則表示小數點后的位數,默認M 為10,D 為0。一般來說,主要用在固定精度的場合,由于其存放長度較大,而且考慮到這種數據完全可以變化形式以整數存放,所以并不是特別推薦。
????????時間存儲格式總類并不是太多,我們常用的主要就是DATETIME,DATE 和TIMESTAMP,從存儲空間來看TIMESTAMP 最少,四個字節,而其他兩種數據類型都是八個字節,多了一倍。而TIMESTAMP 的缺點在于他只能存儲從1970 年之后的時間,而另外兩種時間類型可以存放最早從1001 年開始的時間。但是只要我們不需要使用1970 年之前的時間,最好盡量使用TIMESTAMP 來減少存儲空間的占用。
????????CHAR[(M)]類型屬于靜態長度類型,存放長度完全以字符數來計算,所以最終的存儲長度是基于字符集的。VARCHAR[(M)]屬于動態存儲長度類型,僅存占用實際存儲數據的長度。TINYTEXT,TEXT,MEDIUMTEXT 和LONGTEXT 這四種類型同屬于一種存儲方式,都是動態存儲長度類型,不同的僅僅是最大長度的限制。
18.MySQL Server 性能優化
? ??源碼包的編譯參數推薦
19.MySQL 日志設置優化
? ??在默認情況下,系統僅僅打開錯誤日志,關閉了其他所有日志,但是在一般稍微重要一點的實際應用場景中,都至少需要打開二進制日志,因為這是MySQL很多存儲引擎進行增量備份的基礎,也是MySQL 實現復制的基本條件。一般情況下,在生產系統中最好關閉查詢日志,減少io負擔。
? ??Binlog 相關參數及優化策略:
? ? ? ? 查看相關參數命令 show variables like '%binlog%';
? ??????binlog_cache_size:在事務過程中容納二進制日志SQL 語句的緩存大小,注意,是每個Client 都可以分配設置大小的binlog cache 空間。可以通過MySQL 的以下兩個狀態變量來判斷當前的binlog_cache_size 的狀況:Binlog_cache_use 和Binlog_cache_disk_use。
? ? ? ? max_binlog_cache_size:和"binlog_cache_size"相對應,但是所代表的是binlog 能夠使用的最大cache 內存大小。
? ??????max_binlog_size:Binlog 日志最大值,一般來說設置為512M 或者1G,但不能超過1G。
? ??????sync_binlog:這個參數是對于MySQL 系統來說是至關重要的,他不僅影響到Binlog 對MySQL 所帶來的性能損耗,而且還影響到MySQL 中數據的完整性。對于“sync_binlog”參數的各種設置的說明如下: 1)sync_binlog=0,當事務提交之后,MySQL 不做fsync 之類的磁盤同步指令刷新binlog_cache 中的信息到磁盤,而讓Filesystem 自行決定什么時候來做同步,或者cache 滿了之后才同步到磁盤。2)sync_binlog=n,當每進行n 次事務提交之后,MySQL 將進行一次fsync 之類的磁盤同步指令來將binlog_cache 中的數據強制寫入磁盤。
????Slow Query Log 相關參數及使用建議:
? ? ? ? 查看慢查詢相關設置:show variables like 'slow_query%';
????????????????????????????????????????????show variables like 'long_query%';
20.連接池相關優化
? ??網絡連接的性能配置項:
? ??????max_conecctions:整個MySQL 允許的最大連接數。 這個參數主要影響的是整個MySQL 應用的并發處理能力,當系統中實際需要的連接量大于max_conecctions 的情況下,由于MySQL 的設置限制,那么應用中必然會產生連接請求的等待,從而限制了相應的并發量。所以一般來說,只要MySQL 主機性能允許,都是將該參數設置的盡可能大一點。一般來說500 到800 左右是一個比較合適的參考值
? ??????max_user_connections:每個用戶允許的最大連接數,針對于單個用戶的連接限制。在一般情況下我們可能都較少使用這個限制
? ??????net_buffer_length:網絡包傳輸中,傳輸消息之前的net buffer 初始化大小;這個參數主要可能影響的是網絡傳輸的效率,由于該參數所設置的只是消息緩沖區的初始化大小,所以造成的影響主要是當我們的每次消息都很大的時候MySQL 總是需要多次申請擴展該緩沖區大小。系統默認大小為16KB,一般來說可以滿足大多數場景,當然如果我們的查詢都是非常小,每次網絡傳輸量都很少,而且系統內存又比較緊缺的情況下,也可以適當將該值降低到8KB。
? ??????max_allowed_packet:在網絡傳輸中,一次傳消息輸量的最大值。這個參數net_buffer_length 相對應,只不過是net buffer 的最大值。當我們的消息傳輸量大于net_buffer_length 的設置時,MySQL 會自動增大net buffer 的大小,直到緩沖區大小達到max_allowed_packet 所設置的值。系統默認值為1MB,最大值是1GB,必須設定為1024 的倍數,單位為字節。
? ??????back_log:在MySQL 的連接請求等待隊列中允許存放的最大連接請求數。
?????相關的系統參數及狀態變量說明如下:
? ??????thread_cache_size:Thread Cache 池中應該存放的連接線程數。在短連接的應用系統中,thread_cache_size 的值應該設置的相對大一些
? ??????thread_stack:每個連接線程被創建的時候,MySQL 給他分配的內存大小。當MySQL 創建一個新的連接線程的時候,是需要給他分配一定大小的內存堆棧空間,以便存放客戶端的請求Query 以及自身的各種狀態和處理信息。
? ??????show status like 'connections':系統被連接的次數?
? ??????show status like '%thread%':當前系統中連接線程的狀態
21.Sort Buffer,Join Buffer 和Read Buffer
? ? 查看相關配置信息:show variables like '%buffer%';可以查看join_buffer_size和sort_buffer_size。
? ??join_buffer_size :當我們的Join 是ALL , index ,rang 或者index_merge 的時候使用的Buffer;實際上這種Join 被稱為Full Join。實際上參與Join 的每一個表都需要一個Join Buffer,所以在Join 出現的時候,至少是兩個。Join Buffer 的設置在MySQL 5.1.23 版本之前最大為4GB,但是從5.1.23 版本開始,在除了Windows 之外的64 位的平臺上可以超出4BG 的限制。系統默認128KB。
sort_buffer_size:系統中對數據進行排序的時候使用的Buffer;Sort Buffer 同樣是針對單個Thread的,所以當多個Thread 同時進行排序的時候,系統中就會出現多個Sort Buffer。一般我們可以通過增大Sort Buffer 的大小來提高ORDER BY 或者是GROUP BY的處理性能。系統默認大小為2MB,最大限制和Join Buffer 一樣,在MySQL 5.1.23 版本之前最大為4GB,從5.1.23 版本開始,在除了Windows 之外的64 位的平臺上可以超出4GB 的限制。
? ??如果應用系統中很少有Join 語句出現,則可以不用太在乎join_buffer_size 參數的大小設置,但是如果Join 語句不是很少的話,個人建議可以適當增大join_buffer_size 的設置到1MB 左右,如果內存充足甚至可以設置為2MB。對于sort_buffer_size 參數來說,一般設置為2MB 到4MB 之間可以滿足大多數應用的需求。
22.MyI SAM存儲引擎優化
? ??MyISAM 存儲引擎的索引和數據是分開存放于“.MYI”文件中,每個“.MYI”文件由文件頭和實際的索引數據。“.MYI”的文件頭中主要存放四部分信息,分別稱為:state(主要是整個索引文件的基本信息),base(各個索引的相關信息,主要是索引的限制信息), keydef(每個索引的定義信息)和recinfo(每個索引記錄的相關信息)。在文件頭后面緊接著的就是實際的索引數據信息了。索引數據以Block(Page)為最小單位,每個block 中只會存在同一個索引的數據,這主要是基于提高索引的連續讀性能的目的。在MySQL 中,索引文件中索引數據的block 被稱為Index Block,每個Index Block 的大小并不一定相等。
? ??在“.MYI”中,Index Block 的組織形式實際上只是一種邏輯上的,并不是物理意義上的。在物理上,實際上是以File Block 的形式來存放在磁盤上面的。在Key Cache 中緩存的索引信息是以“Cache Block”的形式組織存放的,“Cache Block”是相同大小的,和“.MYI”文件物理存儲的Block( File Block ) 一樣。在一條Query 通過索引檢索表數據的時候, 首先會檢查索引緩存(key_buffer_cache)中是否已經有需要的索引信息,如果沒有,則會讀取“.MYI”文件,將相應的索引數據讀入Key Cache 中的內存空間中,同樣也是以Block 形式存放,被稱為Cache Block。不過,數據的讀入并不是以Index Block 的形式來讀入,而是以File Block 的形式來讀入的。以File Block 形式讀入到Key Cache 之后的Cache Block 實際上是于File Block 完全一樣的。如下圖所示:
? ? 索引緩存優化
????????MyISAM 索引緩存相關的幾個系統參數和狀態參數:
? ??????◆ key_buffer_size,索引緩存大小;
? ? ? ? ? ? 這個參數用來設置整個MySQL 中的常規Key Cache 大小。一般來說,如果我們的MySQL 是運行在32 位平臺紙上,此值建議不要超過2GB 大小。如果是運行在64 位平臺紙上則不用考慮此限制,但也最好不要超過4GB。
? ??????◆ key_buffer_block_size,索引緩存中的Cache Block Size;
? ? ? ? ? ? 在Key Cache 中的所有數據都是以Cache Block 的形式存在,而key_buffer_block_size 就是設置每個Cache Block 的大小,實際上也同時限定了我們將“.MYI”文件中的Index Block 被讀入時候的File Block 的大小。
? ??????◆ key_cache_division_limit,LRU 鏈表中的Hot Area 和Warm Area 分界值;
? ??????????實際上,在MySQL 的Key Cache 中所使用的LRU 算法并不像傳統的算法一樣僅僅只是通過訪問頻率以及最后訪問時間來通過一個唯一的鏈表實現,而是將其分成了兩部分。一部分用來存放使用比較頻繁的Hot Cacke Lock(Hot Chain),被成為Hot Area,另外一部分則用來存放使用不是太頻繁的Warm Cache Block(Warm Chain),被成為Warm Area。這樣做的目的主要是為了保護使用比較頻繁的Cache Block 更不容易被換出。而key_cache_division_limit 參數則是告訴MySQL該如何劃分整個Cache Chain劃分為Hot Chain和Warm Chain 兩部分,參數值為WarmChain 占整個Chain 的百分比值。設置范圍1~100,系統默認為100,也就是只有Warm Chain。
? ??????◆ key_cache_age_threshold,控制Cache Block 從Hot Area 降到Warm Area 的限制;????????
? ??????????key_cache_age_threshold參數控制Hot Area 中的Cache Block 何時該被降級到Warm Area 中。系統默認值為300,最小可以設置為100。值越小,被降級的可能性越大。
? ??key_buffer_size計算指標:Key_Size = key_number * (key_length+4)/0.67
? ??Key Cache 的命中率:
? ??????Cache 相關的性能狀態參數變量。
????????◆ Key_blocks_not_flushed,已經更改但還未刷新到磁盤的Dirty Cache Block;
????????◆ Key_blocks_unused,目前未被使用的Cache Block 數目;
????????◆ Key_blocks_used,已經使用了的Cache Block 數目;
????????◆ Key_read_requests,Cache Block 被請求讀取的總次數;
????????◆ Key_reads,在Cache Block 中找不到需要讀取的Key 信息后到“.MYI”文件中讀取的次數;
????????◆ Key_write_requests,Cache Block 被請求修改的總次數;
????????◆ Key_writes,在Cache Block 中找不到需要修改的Key 信息后到“.MYI”文件中讀入再修改的次
數;????
? ??????Key_buffer_UsageRatio = (1 - Key_blocks_used/(Key_blocks_used + Key_blocks_unused)) *
100%? ? ? ? ? ? //緩存使用率,如果該值過低說明key_bufffer_size設置過大。
? ? ? ??Key_Buffer_Read_HitRatio = (1 - Key_reads/Key_read_requests) * 100%? ? //緩存命中率,如果該值較低可能是key_buffer_size設置較小;或key_cache_age_thresholdkey_cache_division_limit的設置不當,造成Key Cache cache失效太快。
????多Key Cache 的使用?
? ??????MySQL 官方建議在比較繁忙的系統上一般可以設置三個Key Cache:
????????????一個Hot Cache 使用20%的大小用來存放使用非常頻繁且更新很少的表的索引;
????????????一個Cold Cache 使用20%的大小用來存放更新很頻繁的表的索引;
????????????一個Warm Cache 使用剩下的60%空間,作為整個系統默認的Key Cache;
? ??Key Cache 預加載:LOAD INDEX INTO CACHE tb_name_list ...; 對于這種啟動后立即加載的操作,可以利用MySQL 的init_file 參數來設置相關的命令,如下:
? ??表讀取緩存優化
????????在MySQL 中有兩種讀取數據文件的緩沖區,一種是Sequential Scan 方式(如全表掃描)掃描表數據的時候使用,另一種則是在Random Scan(如通過索引掃描)的時候使用。雖然這兩種文件讀取緩沖區并不是MyISAM 存儲引擎所特有的,但是由于MyISAM 存儲引擎并不會Cache 數據(.MYD)文件,每次對數據文件的訪問都需要通過調用文件系統的相關指令從磁盤上面讀取物理文件。所以,每次讀取數據文件需要使用的內存緩沖區的設置就對數據文件訪問的性能非常重要了。
? ??◆ read_buffer_size,以Sequential Scan 方式掃描表數據時候使用的Buffer;
? ? ? ??每個Thread 進行Sequential Scan 的時候都會產生該Buffer,所以在設置的時候盡量不要太高,避免因為并發太大造成內存不夠。一般來說,可以嘗試適當調大此參數看是否能夠改善全表掃描的性能。
? ??◆ read_rnd_buffer_size,進行Random Scan 的時候使用的Buffer;
? ??????一般來說,read_rnd_buffer_size 值的適當調大,對提高ORDER BY 操作的性能有一定的效果。
并發優化
? ??由于MyISAM 存儲引擎的表級鎖定機制,以及讀寫互斥的問題,其并發寫的性能較差。如果覺得光靠Key Cache 來緩存索引還是不夠快的話,我們還可以通過Query Cache 功能來直接緩存Query 的結果集。
? ??1. 打開concurrent_insert 的功能,提高INSERT 操作和SELECT 之間的并發處理,大部分情況下concurrent_insert 的值都被設置為1,當表中沒有刪除記錄留下的空余空間的時候都可以在尾部并行插入。如果我們的系統主要以寫為主,尤其是有大量的INSERT 的時候。為了盡可能提高INSERT 的效率,我們可以將concurrent_insert 設置為2,也就是告訴MyISAM,不管在表中是否有刪除行留下的空余空間,都在尾部進行并發插入,使INSERT 和SELECT 能夠互不干擾。
? ??2. 控制寫入操作的大小,盡量讓每次寫入操作都能夠很快的完成
? ??3. 通過犧牲讀取效率來提高寫入效率。為了盡可能讓寫入更快,可以適當調整讀和寫的優先級別,讓寫入操作的優先級高于讀操作的優先級。
????除了上面我們分析的這幾個方面之外,MyISAM還存在其他一些可以優化的地方和一些常用的優化技巧。1. 通過OPTIMIZE 命令來整理MyISAM 表的文件? ?2. 設置myisam_max_[extra]_sort_file_size 足夠大,對REPAIR TABLE 的效率可能會有較大改善。3. 在執行CREATE INDEX 或者REPAIR TABLE 等需要大的排序操作的之前可以通過調整session 級別的myisam_sort_buffer_size 參數值來提高排序操作的效率。4. 通過打開delay_key_write 功能,減少IO 同步的操作,提高寫入性能。5. 通過調整bulk_insert_buffer_size 來提高INSERT...SELECT...這樣的bulk insert 操作的整體性能,LOAD DATA INFILE...的性能也可以得到改善。
23.I nnodb 存儲引擎優化
? ??Innodb 存儲引擎和MyISAM 存儲引擎最大區別主要有四點,第一點是緩存機制(索引+數據),第二點是事務支持,第三點是鎖定實現(行級鎖定),最后一點就是數據存儲方式的差異(共享表空間)。
? ??無論是對于哪一種數據庫來說,緩存技術都是提高數據庫性能的關鍵技術,物理磁盤的訪問速度永遠都會與內存的訪問速度永遠都不是一個數量級的。通過緩存技術無論是在讀還是寫方面都可以大大提高數據庫整體性能。
Innodb_buffer_pool_size 的合理設置
? ? 可以同過show status like 'Innodb_buffer_pool_%' 指令查看Buffer pool使用情況
? ? 上面的值可以看出總共有8192pages,還有6765是free狀態,只有1420個pages有數據,read請求47848次,其中1066次請求buffer pool中沒有,也就是說有1066次是通過讀取物理磁盤獲取數據的,很容易的出read命中率大概為:(47848-1066)/47848*100%=97.7%
? ??當然,通過上面的數據,我們還可以分析出write 命中率,可以得到發生了多少次read_ahead_rnd,多少次read_ahead_seq,發生過多少次latch,多少次因為Buffer 空間大小不足而產生wait_free 等等。
? ??單從這里的數據來看,我們設置的Buffer Pool 過大,僅僅使用1420/ 8192* 100% = 17.33%。
innodb_log_buffer_size 參數的使用
? ??顧名思義,這個參數就是用來設置Innodb 的Log Buffer 大小的,系統默認值為1MB。Log Buffer的主要作用就是緩沖Log 數據,提高寫Log 的IO 性能。一般來說,如果你的系統不是寫負載非常高且以大事務居多的話,8MB 以內的大小就完全足夠了。
? ? 查看log buffer使用情況:show status like 'innodb_log%';
? ??如果完全從Log Buffer 本身來說,自然是大一些會減少更多的磁盤IO。但是由于Log 本身是為了保護數據安全而產生的,而Log 從Buffer 到磁盤的刷新頻率和控制數據安全一致的事務直接相關,并且也有相關參數來控制(innodb_flush_log_at_trx_commit)所以得進行權衡。
24.事務優化
? ??Innodb 的事務隔離級別:
? ? ? ? 1.READ UNCOMMITTED:常被成為Dirty Reads(臟讀),最低隔離級別,在普通的非鎖定模式下SELECT 的執行使我們看到的數據可能并不是查詢發起時間點的數據,因而在這個隔離度下是非Consistent Reads(一致性讀);
? ??????2. READ COMMITTED:這一隔離級別下,不會出現Dirty Read,但是可能出現Non-Repeatable Reads(不可重復讀)和Phantom Reads(幻讀)。屬于語句級別的隔離,如通過SELECT ... FOR UPDATE 和SELECT ... LOCK IN SHARE MODE 來執行的請求僅僅鎖定索引記錄,而不鎖定之前的間隙,因而允許在鎖定的記錄后自由地插入新記錄。
? ??????3. REPEATABLE READ:InnoDB 默認的事務隔離級別。在這一級中,同一事務中所有的Consistent Reads 均讀取第一次讀取時已確定的快照。在REPEATABLE READ 隔離級別下,不會出現Dirty Reads,也不會出現Non-Repeatable Reads,但是仍然存在Phantom Reads 的可能性。SELECT ... FOR UPDATE, SELECT... LOCK IN SHARE MODE, UPDATE, 和DELETE ,這些以唯一條件搜索唯一索引的,只鎖定所找到的索引記錄,而不鎖定該索引之前的間隙。
? ? ? ? 4.SERIALIZABLE:。設置為SERIALIZABLE 隔離級別之后,在事務中的任何時候所看到的數據都是事務啟動時刻的狀態。不論在這期間有沒有其他事務已經修改了某些數據并提交。所以,SERIALIZABLE 事務隔離級別下,Phantom Reads 也不會出現。(幻讀:并不是說兩次讀取獲取的結果集不同,幻讀側重的方面是某一次的 select 操作得到的結果所表征的數據狀態無法支撐后續的業務操作。更為具體一些:select 某記錄是否存在,不存在,準備插入此記錄,但執行 insert 時發現此記錄已存在,無法插入,此時就發生了幻讀)
解決不可重復讀的方法是?鎖行,解決幻讀的方式是?鎖表
25.悲觀鎖和樂觀鎖
數據庫中的樂觀鎖和悲觀鎖以及實現方式
樂觀鎖:獲取數據時不會考慮并發情況造成的數據沖突,然后再數據更新提交時正式對數據的沖突與否進行檢測,如果發現沖突了,則返回錯誤信息,讓用戶重新操作。
悲觀鎖:總是做最壞的打算,每次去讀取數據都會認為會被其它線程修改,所以會加鎖,當其它線程想要訪問數據時,都需要阻塞掛起。
樂觀鎖實現方式
version方式:
一般在數據表中加一個version版本字段,表示數據被修改的版本次數,當數據被修改時,version會被加一。當線程A讀取數據時也要同時讀取version值,在提交更新的時候,如果剛才讀取的version值和當前數據庫里的version值一致,那么才能更新,否則重新更新操作,直到更新成成功。樂觀鎖在獲得鎖的同時已經完成了更新操作
SQL代碼實現:
悲觀鎖實現方式
for update方式:
一般使用select … for update 對所選擇的數據加鎖,例如 select * from t_goods where id =1 for update, 這條sql語句就鎖定了t_goods表中符合id=1的這條記錄,本次事務提交之前,外界無法修改這些記錄。悲觀鎖遵循一鎖、二判、三更新、四釋放的原則