1 初識索引
索引在MySQL中也叫是一種「鍵」,是存儲引擎用於快速找到記錄的一種數據結構。html
索引對於良好的性能很是關鍵,尤爲是當表中的數據量愈來愈大時,索引對於性能的影響愈發重要。索引優化應該是對查詢性能優化最有效的手段了。索引可以輕易將查詢性能提升好幾個數量級。mysql
索引至關於字典的音序表,若是要查某個字,若是不使用音序表,則須要從幾百頁中逐頁去查。sql
2 索引的原理
索引的目的在於提升查詢效率,與咱們查閱圖書所用的目錄是一個道理:先定位到章,而後定位到該章下的一個小節,而後找到頁數。類似的例子還有:查字典,查火車車次,飛機航班等數據庫
本質都是:經過不斷地縮小想要獲取數據的範圍來篩選出最終想要的結果,同時把隨機的事件變成順序的事件,也就是說,有了這種索引機制,咱們能夠老是用同一種查找方式來鎖定數據。vim
2.1 B+樹
### b+樹性質 1.索引字段要儘可能的小: 咱們知道IO次數取決於b+數的高度h,假設當前數據表的數據爲N,每一個磁盤塊的數據項的數量是m,則有h=㏒(m+1)N,當數據量N必定的狀況下,m越大,h越小;而m = 磁盤塊的大小 / 數據項的大小,磁盤塊的大小也就是一個數據頁的大小,是固定的,若是數據項佔的空間越小,數據項的數量越多,樹的高度越低。這就是爲何每一個數據項,即索引字段要儘可能的小,好比int佔4字節,要比bigint8字節少一半。這也是爲何b+樹要求把真實的數據放到葉子節點而不是內層節點,一旦放到內層節點,磁盤塊的數據項會大幅度降低,致使樹增高。當數據項等於1時將會退化成線性表。 2.索引的最左匹配特性: 當b+樹的數據項是複合的數據結構,好比(name,age,sex)的時候,b+數是按照從左到右的順序來創建搜索樹的,好比當(張三,20,F)這樣的數據來檢索的時候,b+樹會優先比較name來肯定下一步的所搜方向,若是name相同再依次比較age和sex,最後獲得檢索的數據;但當(20,F)這樣的沒有name的數據來的時候,b+樹就不知道下一步該查哪一個節點,由於創建搜索樹的時候name就是第一個比較因子,必需要先根據name來搜索才能知道下一步去哪裏查詢。好比當(張三,F)這樣的數據來檢索時,b+樹能夠用name來指定搜索方向,但下一個字段age的缺失,因此只能把名字等於張三的數據都找到,而後再匹配性別是F的數據了, 這個是很是重要的性質,即索引的最左匹配特性。
2.2 聚合索引與輔助索引
數據庫中的B+樹索引能夠分爲彙集索引(clustered index)和輔助索引(secondary index),性能優化
彙集索引與輔助索引相同的是:不論是彙集索引仍是輔助索引,其內部都是B+樹的形式,即高度是平衡的,葉子結點存放着全部的數據。服務器
彙集索引與輔助索引不一樣的是:葉子結點存放的是不是一整行的信息數據結構
3 MySQL索引
3.1 瞭解索引
## 索引的功能
1. 索引的功能就是加速查找2. mysql中的primary key,unique,聯合惟一也都是索引,這些索引除了加速查找之外,還有約束的功能
## 建立/刪除索引的語法 ## #方法一:建立表時 CREATE TABLE 表名 ( 字段名1 數據類型 [完整性約束條件…], 字段名2 數據類型 [完整性約束條件…], [UNIQUE | FULLTEXT | SPATIAL ] INDEX | KEY [索引名] (字段名[(長度)] [ASC |DESC]) ); #方法二:CREATE在已存在的表上建立索引 CREATE [UNIQUE | FULLTEXT | SPATIAL ] INDEX 索引名 ON 表名 (字段名[(長度)] [ASC |DESC]) ; #方法三:ALTER TABLE在已存在的表上建立索引 ALTER TABLE 表名 ADD [UNIQUE | FULLTEXT | SPATIAL ] INDEX 索引名 (字段名[(長度)] [ASC |DESC]) ; #刪除索引:DROP INDEX 索引名 ON 表名字;
3.2 索引類型
#### 經常使用索引 #### #一、普通索引INDEX:加速查找 #二、惟一索引: -主鍵索引PRIMARY KEY:加速查找+約束(不爲空、不能重複) -惟一索引UNIQUE:加速查找+約束(不能重複) #三、聯合索引: -PRIMARY KEY(id,name):聯合主鍵索引 -UNIQUE(id,name):聯合惟一索引 -INDEX(id,name):聯合普通索引
# 組合索引(最左前綴匹配): - create unique index 索引名稱 on 表名(列名,列名) - drop unique index 索引名稱 on 表名 - create index ix_name_email on userinfo3(name,email,) - 最左前綴匹配【必定要包含最左邊的】 √ select * from userinfo3 where name='alex'; √ select * from userinfo3 where name='alex' and email='asdf'; × select * from userinfo3 where email='alex@qq.com'; # 組合索引效率 > 索引合併 組合索引 - (name,email,) select * from userinfo3 where name='alex' and email='asdf'; select * from userinfo3 where name='alex'; 索引合併【把多個單列索引合併使用】: - name - email select * from userinfo3 where name='alex' and email='asdf'; select * from userinfo3 where name='alex'; select * from userinfo3 where email='asdf';
#覆蓋索引:在索引文件中直接獲取數據。 即從輔助索引中就能夠獲得查詢記錄,而不須要查詢彙集索引中的記錄。
4 正確使用索引
(1)範圍問題,或者說條件不明確,條件中出現這些符號或關鍵字:>、>=、<、<=、!= 、between...and...、like、大於號、小於號ide
(2)儘可能選擇區分度高的列做爲索引,區分度的公式是count(distinct col)/count(*),表示字段不重複的比例,比例越大咱們掃描的記錄數越少,惟一鍵的區分度是1,而一些狀態、性別字段可能在大數據面前區分度就是0函數
(3)索引列不能在條件中參與計算,保持列「乾淨」,好比from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,緣由很簡單,b+樹中存的都是數據表中的字段值,但進行檢索時,須要把全部元素都應用函數才能比較,顯然成本太大。因此語句應該寫成create_time = unix_timestamp(’2014-05-29’)
(4)and/or
#一、and與or的邏輯 條件1 and 條件2:全部條件都成立纔算成立,但凡要有一個條件不成立則最終結果不成立 條件1 or 條件2:只要有一個條件成立則最終結果就成立 #二、and的工做原理 條件: a = 10 and b = 'xxx' and c > 3 and d =4 索引: 製做聯合索引(d,a,b,c) 工做原理: 對於連續多個and:mysql會按照聯合索引,從左到右的順序找一個區分度高的索引字段(這樣即可以快速鎖定很小的範圍),加速查詢,即按照d—>a->b->c的順序 #三、or的工做原理 條件: a = 10 or b = 'xxx' or c > 3 or d =4 索引: 製做聯合索引(d,a,b,c) 工做原理: 對於連續多個or:mysql會按照條件的順序,從左到右依次判斷,即a->b->c->d
(5)最左前綴匹配原則
(6)其餘注意事項
- 避免使用select *
- 使用count(1)
- 建立表時儘可能使用 char 代替 varchar - 表的字段順序固定長度的字段優先 - 組合索引代替多個單列索引(因爲mysql中每次只能使用一個索引,因此常用多個條件查詢時更適合使用組合索引) - 儘可能使用短索引 - 使用鏈接(JOIN)來代替子查詢(Sub-Queries) - 連表時注意條件類型需一致 - 索引散列值(重複少)不適合建索引,例:性別不適合
5 查詢優化神器-explain
優化語句基本上都是在優化rows。具體用法和字段含義能夠參考官網 explain-output
# 執行計劃:讓mysql預估執行操做(通常正確) all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const #id,email # 慢: select * from userinfo3 where name='alex' explain select * from userinfo3 where name='alex' type: ALL(全表掃描) select * from userinfo3 limit 1;
# 快: select * from userinfo3 where email='alex' type: const(走索引)
6 慢查詢優化的基本步驟
# 0.先運行看看是否真的很慢,注意設置SQL_NO_CACHE # 1.where條件單表查,鎖定最小返回記錄表。這句話的意思是把查詢語句的where都應用到表中返回的記錄數最小的表開始查起,單表每一個字段分別查詢,看哪一個字段的區分度最高 # 2.explain查看執行計劃,是否與1預期一致(從鎖定記錄較少的表開始查詢) # 3.order by limit 形式的sql語句讓排序的表優先查 # 4.瞭解業務方使用場景 # 5.加索引時參照建索引的幾大原則 # 6.觀察結果,不符合預期繼續從0分析
7 慢日誌管理
# 慢日誌 - 執行時間 > 10 - 未命中索引 - 日誌文件路徑 配置: - 內存 show variables like '%query%'; show variables like '%queries%'; set global 變量名 = 值 - 配置文件 mysqld --defaults-file='E:\wupeiqi\mysql-5.7.16-winx64\mysql-5.7.16-winx64\my-default.ini' my.conf內容: slow_query_log = ON slow_query_log_file = D:/.... # 注意:修改配置文件以後,須要重啓服務
MySQL日誌管理
======================================================== 錯誤日誌: 記錄 MySQL 服務器啓動、關閉及運行錯誤等信息 二進制日誌: 又稱binlog日誌,以二進制文件的方式記錄數據庫中除 SELECT 之外的操做 查詢日誌: 記錄查詢的信息 慢查詢日誌: 記錄執行時間超過指定時間的操做 中繼日誌: 備庫將主庫的二進制日誌複製到本身的中繼日誌中,從而在本地進行重放 通用日誌: 審計哪一個帳號、在哪一個時段、作了哪些事件 事務日誌或稱redo日誌: 記錄Innodb事務相關的如事務執行時間、檢查點等 ======================================================== # 1、bin-log 1. 啓用 # vim /etc/my.cnf [mysqld] log-bin[=dir\[filename]] # service mysqld restart 2. 暫停 //僅當前會話 SET SQL_LOG_BIN=0; SET SQL_LOG_BIN=1; 3. 查看 查看所有: # mysqlbinlog mysql.000002 按時間: # mysqlbinlog mysql.000002 --start-datetime="2012-12-05 10:02:56" # mysqlbinlog mysql.000002 --stop-datetime="2012-12-05 11:02:54" # mysqlbinlog mysql.000002 --start-datetime="2012-12-05 10:02:56" --stop-datetime="2012-12-05 11:02:54" 按字節數: # mysqlbinlog mysql.000002 --start-position=260 # mysqlbinlog mysql.000002 --stop-position=260 # mysqlbinlog mysql.000002 --start-position=260 --stop-position=930 4. 截斷bin-log(產生新的bin-log文件) a. 重啓mysql服務器 b. # mysql -uroot -p123 -e 'flush logs' 5. 刪除bin-log文件 # mysql -uroot -p123 -e 'reset master' # 2、查詢日誌 啓用通用查詢日誌 # vim /etc/my.cnf [mysqld] log[=dir\[filename]] # service mysqld restart # 3、慢查詢日誌 3.1 啓用慢查詢日誌 # vim /etc/my.cnf [mysqld] log-slow-queries[=dir\[filename]] long_query_time=n # service mysqld restart MySQL 5.6: slow-query-log=1 slow-query-log-file=slow.log long_query_time=3 單位爲秒 3,2 查看慢查詢日誌 測試:BENCHMARK(count,expr) SELECT BENCHMARK(50000000,2*3);
6 慢查詢優化的基本步驟
# 0.先運行看看是否真的很慢,注意設置SQL_NO_CACHE # 1.where條件單表查,鎖定最小返回記錄表。這句話的意思是把查詢語句的where都應用到表中返回的記錄數最小的表開始查起,單表每一個字段分別查詢,看哪一個字段的區分度最高 # 2.explain查看執行計劃,是否與1預期一致(從鎖定記錄較少的表開始查詢) # 3.order by limit 形式的sql語句讓排序的表優先查 # 4.瞭解業務方使用場景 # 5.加索引時參照建索引的幾大原則 # 6.觀察結果,不符合預期繼續從0分析
7 慢日誌管理
# 慢日誌 - 執行時間 > 10 - 未命中索引 - 日誌文件路徑 配置: - 內存 show variables like '%query%'; show variables like '%queries%'; set global 變量名 = 值 - 配置文件 mysqld --defaults-file='E:\wupeiqi\mysql-5.7.16-winx64\mysql-5.7.16-winx64\my-default.ini' my.conf內容: slow_query_log = ON slow_query_log_file = D:/.... # 注意:修改配置文件以後,須要重啓服務