mysql優化
在日常的開發中,我們大多數都是和數據庫打交道的。而數據庫在項目中其着至關重要的作用,因此數據庫優化的實現,對我們的項目有着非常顯著的作用。而一般的數據庫庫優化可以分爲下面幾個方面。
設計方面
- 字段類型的選項,根據存儲數據的長度儘可能的佔用更少的存儲空間,儘可能定長,儘可能使用整數代替字符,像存儲ip可以轉換成整數進行存儲。
- 實體間的關係設計
- 範式的選擇
- 存儲引擎的選擇,我們一般用到的是innodb和mysiam,
- MyISAM: 擅長處理快速的查詢和插入. 典型的web程序的形態.
- Innodb: 擅長大量併發, 處理大量的更新操作. 支持事務, 外鍵約束.
功能方面
- 索引,使用索引,共分爲四種,普通索引,唯一索引,主鍵索引,全文索引。
- 查詢緩存,可以修改配置文件,進行查詢數據的緩存。
- 分表分區,使用partition關鍵字進行分區,然後根據插入的數據,根據分區算法,算出要存儲到那個分區,常用的分區算法:
- hash,均勻分配,提供一個整數值字段, 利用該字段的值, 對分區數量進行求餘, 劃分分區。
- key,支持非整數字段, 先利用該字段, 計算整數值(類似crc32), 然後, 再求餘運算.
- list,需要提供每個分區所存儲數據的邏輯條件. 滿足條件的數據, 可以被存儲到該分區中。
- range,提供一個小於表達式, 作爲分區的條件。僅僅支持小於表達式。
架構層面
- 負載均衡集羣,將負載(工作任務,訪問請求)進行平衡、分攤到多個操作單元(服務器,數據庫)上進行執行。是解決高性能,單點故障(高可用),擴展性(水平伸縮)的終極解決方案。
- 讀寫分離的處理,將讀,寫操作, 分開到不同的MySQL服務器完成. 稱之爲讀寫分離.注意主從複製。
- 冷熱數據分離,常用與不常用的數據分開。
應用層面(SQL應該如何寫)
- 多表聯查
- 單表查詢
- 儘可能避免哪些低效的SQL
索引
索引(index): 採用完整數據中的部分內容作爲關鍵字, 建立於完整數據位置間的 一種映射關係, 稱之爲索引。簡單來說就是關鍵字於記錄位置的映射, 就是索引.
索引是最常規, 最重要的優化措施。在不改變設計結構, 不增加分佈式的數據庫服務器的基礎上, 提升查詢速度!也是性價比最高一種優化措施。
使用索引優點
- 大大加快數據的檢索速度;
- 創建唯一性索引,保證數據庫表中每一行數據的唯一性;
- 加速表和表之間的連接;
- 在使用分組和排序子句進行數據檢索時,可以顯著減少查詢中分組和排序的時間。
但是如要注意的注意的是:索引需要佔物理空間。並且當對錶中的數據進行增加、刪除和修改的時候,索引也要動態的維護,降低了數據的維護速度。
在mysql中共分爲四種索引
- 普通索引,對關鍵字沒有要求。
- 唯一索引,要求關鍵字不能重複。
- 主鍵索引,主鍵自動成爲主鍵索引。
- 全文索引,我們通常使用插件來完成全文索引。
主鍵索引
我們在創建一張表的時候,往往是需要指定一個主鍵的,使用PRIMARY KEY關鍵字進行聲明當前的字段是主鍵字段,主鍵字段是不能重複並且不能爲空的。
主鍵索引的創建
主鍵索引可以在建表的時候,直接指定,也可以在創完表後手動的指定。
建表時指定
create table student_index( id int auto_increment, name varchar(20), -- 建表的時候,直接指定主鍵是哪個字段。 PRIMARY KEY (id) )charset=utf8 engine = myisam;
建表過後指定
alter table student_index add primary key (id);
在一個表中,最多只能有一個主鍵。並且主鍵索引的速度最快,效率最高。主鍵索引通常表的一個字段,整型的,並且是auto_increment(自增長)。
創建完主鍵索引後,可以使用show index from 表名\G指令查看當前表的索引。
mysql> show index from student_index\G
*************************** 1. row ***************************
Table: student_index
Non_unique: 0
Key_name: PRIMARY(索引名)
Seq_in_index: 1
Column_name: id(索引id)
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE(索引類型)
Comment:
Index_comment:
1 row in set (0.13 sec)
主鍵索引的刪除
當我們不想使用主鍵的時候,我們可以刪除主鍵索引,刪除主鍵:
ALTER TABLE 表名 DROP PRIMARY KEY;
刪除主鍵時,如果主鍵時自增長,這時需要把自增長去掉,才能正確的刪除主鍵。
ALTER TABLE student_index modify id int;
刪除完畢後,使用show index from 表名\G,可以看到是爲空的。
唯一索引
當我們在創建表時,希望一個字段的值是不能重複的,我們可以設置當前字段爲唯一索引。使用unique關鍵字進行聲明。
唯一索引的創建
唯一索引的創建也是分爲兩種的,創建表的時候直接指定,創建完畢之後在指定。
建表時指定
create table student_index( id int, name varchar(20), student_id int, -- 指定student_id爲唯一索引 unique key (student_id) )charset=utf8 engine = myisam;
建表過後指定
ALTER TABLE student_index ADD UNIQUE (student_id);
在一個表中可以有多個唯一索引,唯一索引的列的值不能重複,但是可以爲空(如果你設置了)。
創建完唯一索引後,可以使用show index from 表名\G指令查看當前表的索引。
mysql> show index from student_index\G
*************************** 1. row ***************************
Table: student_index
Non_unique: 0
Key_name: student_id
Seq_in_index: 1
Column_name: student_id
Collation: A
Cardinality: NULL
Sub_part: NULL
Packed: NULL
Null: YES
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec)
唯一索引的刪除
當然,我們也可以刪除唯一索引的。
ALTER TABLE 表名 DROP INDEX 索引名;
刪除完畢後,使用show index from 表名\G,可以看到是爲空的。
普通索引
我們在一張表中如果某個字段,不是主鍵,也不是唯一的值,有好多的重複值,這時就可以創建普通索引
普通索引的創建
建表時指定
create table student_index( id int, name varchar(20), student_id int, -- 創建普通索引 index (name) )charset=utf8 engine = myisam;
建表過後指定
ALTER TABLE student_index ADD INDEX (name);
在一個表中,可以有多個普通索引,如果我們某個字段的值,存在重複的記錄,那麼我們只能選擇普通索引,因此普通索引使用的是最多.
使用show index from 表名\G指令查看當前表的索引。
普通索引的刪除
當然,我們也可以刪除普通索引的。
ALTER TABLE 表名 DROP INDEX 索引名;
刪除完畢後,使用show index from 表名\G,可以看到是爲空的。
索引的使用
我們創建索引的目的是爲了提高查找數據的效率,當我們寫完sql語句之後,mysql會根據sql語句的結構,自動的啓用索引,一般是在where,order by,join這三個關鍵字後面的字段如果存在索引,就會啓用索引。
並且如果我們查詢的字段如果是索引,也是會啓用索引的。
在這裏我構建一張大容量的表,數據量爲七百萬條數據,因爲索引只用在數據非常多時候才能看出來明顯的效果。
explain – 獲取執行計劃
explain關鍵字的作用,就是獲取當前sql語句的執行計劃。
當我們從客戶端輸入sql語句到我們得到結果,其中是有一些過程的。
如果我們在sql語句的前面添加explain關鍵字,我們得到的數據就不是查詢的數據而是如圖中的執行計劃。
mysql> explain select * from student where id = 253219\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE -- 簡單的查詢
table: student -- 查詢的那張表
type: const -- 最快的一種查詢,僅僅需要匹配一條記錄
possible_keys: PRIMARY
key: PRIMARY -- 真正會用到的索引
key_len: 4
ref: const
rows: 1 -- 估計需要從數據庫中獲取1條數據即可。
Extra:
1 row in set (0.00 sec)
由sql語句可知,我們的id是主鍵索引,所以在執行計劃中sql開啓可primary索引,進行數據的查找。
如果我們的sql語句中並沒有使用到索引,那麼mysql並不會啓用索引。
mysql> explain select * from student where first_name like '%C%'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: student
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 7855683
Extra: Using where
1 row in set (0.00 sec)
可以看到並沒有開啓索引。
上面我們說過,在where,order by,join關鍵字後面的關鍵字如果有索引,都會啓用索引進行數據的查找,這裏可以使用explain關鍵字,查看執行計劃進行驗證。
索引的創建
在上面我們知道使用索引,會大大的縮短查詢數據的時間,但是我們應該在那些字段上建立索引呢?
創建索引需要了解表的結構,同時明白我們在該表上常執行的sql語句並且統計SQL的權重以及頻率。
結構+操作是決定索引的要素.
同時如果們可以where,orderby, join 所對應的字段後邊增加索引。
索引的數據結構
創建完索引,索引的存儲可以分爲三種:
- BTree索引
- 聚簇索引(B+Tree)
- Hash索引
BTree索引
BTree數據結構是索引存儲在磁盤上的不二選擇。BTree是一中排序完成的結構。可以看成是一個層級的結構,每層中都是排序好的關鍵字。
一個Btree的節點, 存儲多個排序好的索引關鍵字,而關鍵字之間是子節點指針,指向下一個BTree節點。
在圖中可以看到數據是按照某種順序進行排序的,這樣在查詢的時候,就可以快速的得到想要的結果,圖中只是簡單的描述了兩層。
BTree的數據結構最重要的特點: 減少磁盤IO, 增加獲取的關鍵字的數量。一層節點的大小, 取決於一次性磁盤IO的數據大小, 512(K)Bytes. 2者保持一致可以保證, 一次磁盤IO讀取開銷, 儘可能多的獲取關鍵字數量。假設, 關鍵字的大小, 導致一個節點可以存儲1000個關鍵字. 那麼2層的Btree可以存儲
1000 + (1000+1)*1000 = 100w意味着, 2次磁盤開銷 就可以在100w的關鍵字中進行檢索!
MySQL的無論創建的(普通, 唯一, 主鍵, 全文)索引, 都是存在在Btree結構中。
聚簇索引, B+Tree
B+Tree, 是在Btree的基礎上, 做了些調整和一些變化。
當我們mysql的存儲引擎選擇是innodb的時候,我們向數據庫中插入數據, innodb的記錄的順序, 依據表中的主鍵進行排序的。
在MySQL的所有表的索引中, 只有一個索引例外, 不是存儲在BTree結構中, 就是innodb表的主鍵索引.
而是存儲在B+Tree中.B+Tree是一個聚簇(聚集)結構。
典型的結構特徵:
索引的關鍵字是和索引對應的記錄存儲在一起。
由於記錄和主鍵存儲在一起,記錄的位置是不固定。
那麼innodb的非主鍵索引, 不是聚簇的, 存儲記錄位置時, 不是存儲的磁盤位置, 而是存儲的是, 記錄的主鍵值.
如果使用innodb進行檢索, 先是利用關鍵字, 確定主鍵值, 再利用主鍵值, 在聚簇的主索引上, 找到記錄. 需要經過二次檢索。
Hash索引
hash, 利用key可以快速獲取一個對應的值, 就是hash算法.而hash索引, 就是利用關鍵字, 就可以快速的確定關鍵字對應的記錄位置.
hash索引, 利用內存的快速尋址達到的目的。僅僅在磁盤上的索引被載入內存時, 纔會被轉換成hash結構, 便於在內存中快速確定。是內部優化的措施, 而不是存儲磁盤上索引的措施.