############### 索引介紹 ##############
""" 1. 索引介紹 需求: 一般的應用系統,讀寫比例在10:1左右,而且插入操作和一般的更新操作很少出現性能問題,在生產環境中,我們遇到最多的, 也是最容易出問題的,還是一些復雜的查詢操作,因此對查詢語句的優化顯然是重中之重。 說起加速查詢,就不得不提到索引了。 索引: 簡單的說,相當於圖書的目錄,可以幫助用戶快速的找到需要的內容. 在MySQL中也叫做“鍵”,是存儲引擎用於快速找到記錄的一種數據結構。能夠大大提高查詢效率。 特別是當數據量非常大,查詢涉及多個表時,使用索引往往能使查詢速度加快成千上萬倍. 本質: 索引本質:通過不斷地縮小想要獲取數據的范圍來篩選出最終想要的結果, 同時把隨機的事件變成順序的事件,也就是說,有了這種索引機制,我們可以總是用同一種查找方式來鎖定數據。 """
############### 索引方法 ##############
""" 2.索引方法 1. B+TREE 索引 B+樹是一種經典的數據結構,由平衡樹和二叉查找樹結合產生,它是為磁盤或其它直接存取輔助設備而設計的一種平衡查找樹, 在B+樹中,所有的記錄節點都是按鍵值大小順序存放在同一層的葉節點中,葉節點間用指針相連,構成雙向循環鏈表, 非葉節點(根節點、枝節點)只存放鍵值,不存放實際數據。 注意:通常其高度都在2~3層,查詢時可以有效減少IO次數。 b+樹的查找過程 如圖所示,如果要查找數據項30,那么首先會把磁盤塊1由磁盤加載到內存,此時發生一次IO, 在內存中用二分查找確定30在28和65之間,鎖定磁盤塊1的P2指針,內存時間因為非常短(相比磁盤的IO)可以忽略不計, 通過磁盤塊1的P2指針的磁盤地址把磁盤塊由磁盤加載到內存,發生第二次IO,30在28和35之間,鎖定當前磁盤塊的P1指針, 通過指針加載磁盤塊到內存,發生第三次IO,同時內存中做二分查找找到30,結束查詢,總計三次IO。 真實的情況是,3層的b+樹可以表示上百萬的數據,如果上百萬的數據查找只需要三次IO,性能提高將是巨大的, 如果沒有索引,每個數據項都要發生一次IO,那么總共需要百萬次的IO,顯然成本非常非常高。 強烈注意: 索引字段要盡量的小,磁盤塊可以存儲更多的索引. 2. HASH 索引 hash就是一種(key=>value)形式的鍵值對,允許多個key對應相同的value, 但不允許一個key對應多個value,為某一列或幾列建立hash索引,就會利用這一列或幾列的值通過一定的算法計算出一個hash值,對應一行或幾行數據. hash索引可以一次定位,不需要像樹形索引那樣逐層查找,因此具有極高的效率. 3.HASH與BTREE比較: hash類型的索引:查詢單條快,范圍查詢慢 btree類型的索引:b+樹,層數越多,數據量越大,范圍查詢和隨機查詢快(innodb默認索引類型) 不同的存儲引擎支持的索引類型也不一樣 InnoDB 支持事務,支持行級別鎖定,支持 Btree、Hash 等索引,不支持Full-text 索引; MyISAM 不支持事務,支持表級別鎖定,支持 Btree、Full-text 等索引,不支持 Hash 索引; Memory 不支持事務,支持表級別鎖定,支持 Btree、Hash 等索引,不支持 Full-text 索引; NDB 支持事務,支持行級別鎖定,支持 Hash 索引,不支持 Btree、Full-text 等索引; Archive 不支持事務,支持表級別鎖定,不支持 Btree、Hash、Full-text 等索引; """
############### 索引類型 ##############
""" 3.索引類型 MySQL中常見索引有: 普通索引 唯一索引 主鍵索引 組合索引 1.普通索引 普通索引僅有一個功能:加速查詢 #創建表同時添加name字段為普通索引 create table tb1( id int not null auto_increment primary key, name varchar(100) not null, index idx_name(name) ); #單獨為表指定普通索引 create index idx_name on tb1(name); # 刪除索引 drop index idx_name on tb1; #查看索引 show index from tb1; 2.唯一索引 唯一索引有兩個功能:加速查詢 和 唯一約束(可含一個null 值) # 創建表的時候創建 create table tb2( id int not null auto_increment primary key, name varchar(50) not null, age int not null, unique index idx_age (age) ) # 單獨創建 create unique index idx_age on tb2(age); 3.主鍵索引 主鍵有兩個功能:加速查詢 和 唯一約束(不可含null) 注意:一個表中最多只能有一個主鍵索引 # 創建表的時候穿件索引 #方式一: create table tb3( id int not null auto_increment primary key, name varchar(50) not null, age int default 0 ); #方式二: create table tb3( id int not null auto_increment, name varchar(50) not null, age int default 0 , primary key(id) ); # 單獨添加索引 alter table tb3 add primary key(id); # 刪除索引 #方式一 alter table tb3 drop primary key; #方式二: #如果當前主鍵為自增主鍵,則不能直接刪除.需要先修改自增屬性,再刪除 alter table tb3 modify id int ,drop primary key; 4.組合索引 組合索引是將n個列組合成一個索引 其應用場景為:頻繁的同時使用n列來進行查詢,如:where n1 = 'alex' and n2 = 666。 # 創建表的時候穿件索引 create table tb4( id int not null , name varchar(50) not null, age int not null, index idx_name_age (name,age) ) # 單獨添加索引 create index idx_name_age on tb4(name,age); """
############### 聚合索引和輔助索引 ##############
""" 4.聚合索引和輔助索引 數據庫中的B+樹索引可以分為聚集索引和輔助索引 聚集索引:InnoDB表 索引組織表,即表中數據按主鍵B+樹存放,葉子節點直接存放整條數據,每張表只能有一個聚集索引。 1.當你定義一個主鍵時,InnnodDB存儲引擎則把它當做聚集索引 2.如果你沒有定義一個主鍵,則InnoDB定位到第一個唯一索引,且該索引的所有列值均飛空的,則將其當做聚集索引。 3如果表沒有主鍵或合適的唯一索引INNODB會產生一個隱藏的行ID值6字節的行ID聚集索引, 補充:由於實際的數據頁只能按照一顆B+樹進行排序,因此每張表只能有一個聚集索引,聚集索引對於主鍵的排序和范圍查找非常有利. 輔助索引:(也稱非聚集索引)是指葉節點不包含行的全部數據,葉節點除了包含鍵值之外,還包含一個書簽連接,通過該書簽再去找相應的行數據 輔助索引葉節點存放的是主鍵值,獲得主鍵值后,再從聚集索引中查找整行數據。舉個例子,如果在一顆高度為3的輔助索引中查找數據, 首先從輔助索引中獲得主鍵值(3次IO),接着從高度為3的聚集索引中查找以獲得整行數據(3次IO),總共需6次IO。一個表上可以存在多個輔助索引。 總結二者區別: 相同的是:不管是聚集索引還是輔助索引,其內部都是B+樹的形式,即高度是平衡的,葉子結點存放着所有的數據。 不同的是:聚集索引葉子結點存放的是一整行的信息,而輔助索引葉子結點存放的是單個索引列信息. 注意: 1. mysql先去索引表里根據b+樹的搜索原理很快搜索到id為4567890的數據,IO大大降低,因而速度明顯提升 2. 我們可以去mysql的data目錄下找到該表,可以看到添加索引后該表占用的硬盤空間多了 3.如果使用沒有添加索引的字段進行條件查詢,速度依舊會很慢(如圖:) """
############### 注意事項 ##############
""" 5.注意事項 數據庫表中添加索引后確實會讓查詢速度起飛,但前提必須是正確的使用索引來查詢,如果以錯誤的方式使用,則即使建立索引也會不奏效。 即使建立索引,索引也不會生效 1. 避免使用select * 2. 其他數據庫中使用count(1)或count(列) 代替 count(*),而mysql數據庫中count(*)經過優化后,效率與前兩種基本一樣. 3. 創建表時盡量時 char 代替 varchar 4. 表的字段順序固定長度的字段優先 5. 組合索引代替多個單列索引(經常使用多個條件查詢時) 6. 使用連接(JOIN)來代替子查詢(Sub-Queries) 7. 不要有超過4個以上的表連接(JOIN) 8. 優先執行那些能夠大量減少結果的連接。 9. 連表時注意條件類型需一致 10.索引散列值不適合建索引,例:性別不適合 """
############### 慢查詢日志 ##############
""" 6,慢查詢日志 將mysql服務器中影響數據庫性能的相關SQL語句記錄到日志文件,通過對這些特殊的SQL語句分析,改進以達到提高數據庫性能的目的。 慢查詢日志參數: long_query_time : 設定慢查詢的閥值,超出設定值的SQL即被記錄到慢查詢日志,缺省值為10s slow_query_log : 指定是否開啟慢查詢日志 log_slow_queries : 指定是否開啟慢查詢日志(該參數已經被slow_query_log取代,做兼容性保留) slow_query_log_file : 指定慢日志文件存放位置,可以為空,系統會給一個缺省的文件host_name-slow.log log_queries_not_using_indexes: 如果值設置為ON,則會記錄所有沒有利用索引的查詢. 查看 MySQL慢日志信息 #.查詢慢日志配置信息 : show variables like '%query%'; #.修改配置信息 set global slow_query_log = on; 查看不使用索引參數狀態: # 顯示參數 show variables like '%log_queries_not_using_indexes'; # 開啟狀態 set global log_queries_not_using_indexes = on; 查看慢日志顯示的方式 #查看慢日志記錄的方式 show variables like '%log_output%'; #設置慢日志在文件和表中同時記錄 set global log_output='FILE,TABLE'; 測試慢查詢日志 #查詢時間超過10秒就會記錄到慢查詢日志中 select sleep(3) FROM user ; #查看表中的日志 select * from mysql.slow_log; """
############### 數據庫優化方案 ##############
1. 避免全表掃描,首先應考慮在 where 及 orderby 涉及的列上建立索引。 2. 避免在 where 子句中對字段進行 null 值判斷,導致引擎放棄使用索引而進行全表掃描 3. 避免在 where 子句中使用 != 或>操作符,引擎將放棄使用索引而進行全表掃描。 4. 避免在 where 子句中使用or 來連接條件 5. 慎用in 和 not, 可以用 exists 代替 in 6. 慎用 like 'XXX%',要提高效率,可以全文檢索。 7. 應盡量避免在 where 子句中對字段進行表達式操作,如: select id from t where num/2=100 應改為select id from t where num=100*2 8. 避免在where子句中對字段進行函數操作 select id from t where substring(name,1,3)='abc' 改為: select id from t where name like 'abc%' 9. 在使用索引字段作為條件時,如果該索引是復合索引,那么必須使用到該索引中的第一個字段作為條件時才能保證系統使用該索引,否則該索引將不會被使用,
並且應盡可能的讓字段順序與索引順序相一致。(索引的最左前綴原則) 10. 並不是所有索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重復時,SQL查詢可能不會去利用索引,
如一表中有字段sex,male、female幾乎各一半,那么即使在sex上建了索引也對查詢效率起不了作用。 11. 索引不是越多越好,索引可以提高select 的效率,同時也降低 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引。 12. 任何地方都不要使用 select * from t ,用具體的字段列表代替“*” 13. 避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。 14. 在新建臨時表時,如果一次性插入數據量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;
如果數據量不大,為了緩和系統表的資源,應先create table,然后insert。 15. 盡量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。 數據庫中的數據在未進行分庫分表的情況下,隨着時間和業務的發展,庫中的表會越來越多,表中的數據量也會越來越大,相應地,數據操作,增刪改查的開銷也會越來越大 16. 讀寫分離。通過數據庫配置設置, mysql復制時,產生了多個數據副本(備庫),為減少服務器壓力,備庫用於處理讀操作,主庫可同時處理讀寫。
備庫的復制是異步的,無法實時同步,讀寫分離的主要難點也在於備庫上的臟數據。通常如果使用備庫進行讀,一般對數據的實時性要求不能太高。 17. 分庫、分表。 18. 利用緩存存儲經常被查詢的數據。利用redis、memcache
############### 結束線 ##############