Mysql 架構及優化之-索引優化


索引基礎知識

索引幫助mysql高效獲取數據的數據結構 索引(mysql中叫"鍵(key)") 數據越大越重要
索引比如一本書,爲了找到書中特定的話題,查看目錄,得到頁碼mysql

select fruit_name from fruit where id = 5 索引列位於id列,索引按值查找而且返回任何包含該值的行
若是索引了多列數據,那麼列的順序很是重要sql


存儲引擎說明

  • myisam 存儲引擎數據庫

表鎖:myisam 表級鎖 緩存

不支持自動恢復數據:斷電以後 使用以前檢查和執行可能的修復 數據結構

不支持事務:不保證單個命令會完成, 多行update 有錯誤 只有一些行會被更新 併發

只有索引緩存在內存中:mysiam只緩存進程內部的索引 函數

緊密存儲:行被僅僅保存在一塊兒工具

  • Innodb存儲引擎性能

事務性:Innodb支持事務和四種事務隔離級別優化

外鍵:Innodb惟一支持外鍵的存儲引擎 create table 命令接受外鍵

行級鎖:鎖設定於行一級 有很好的併發性

多版本:多版本併發控制

按照主鍵彙集:索引按照主鍵彙集

全部的索引包含主鍵列:索引按照主鍵引用行 若是不把主鍵維持很短 索引就增加很大

優化的緩存:Innodb把數據和內存緩存到緩衝池 自動構建哈希索引

未壓縮的索引:索引沒有使用前綴壓縮

阻塞auto_increment:Innodb使用表級鎖產生新的auto_increment

沒有緩存的count():myisam 會把行數保存在表中 Innodb中的count()會全表或索引掃描


索引類型

索引在存儲引擎實現的,而不是服務層

  • B-tree 索引

大多數談及的索引類型就是B-tree類型, 能夠在create table 和其餘命令使用它
myisam使用前綴壓縮以減少索引,Innodb不會壓縮索引 myiam索引按照行存儲物理位置引用被索引的行,Innodb按照主鍵值引用行
B-tree數據存儲是有序的,按照順序保存了索引的列 加速了數據訪問,存儲引擎不會掃描整個表獲得須要的數據

  • B-tree 索引實例

create table peple(
        last_name  varchar(50) not null , 
        first_name varchar(50) not null ,
        dob date not null ,
        gender enum('m','f') not null ,
        key(last_name,first_name,dob)  #決定索引順序
    )

    使用B-tree索引的查詢類型,很好用於全鍵值、鍵值範圍或鍵前綴查找
    只有在超找使用了索引的最左前綴的時候纔有用
    
    匹配全名:全鍵值匹配和索引中的全部列匹配
             查找叫Tang Kang 出生於 1991-09-23 的人 
             
    匹配最左前綴:B-tree找到姓爲tang的人
    
    匹配列前綴: 匹配某列的值的開頭部分 查找姓氏以T開頭的人         
             
    匹配範圍值:索引查找姓大於Tang小於zhu的人
    
    精確匹配一部分而且匹配某個範圍的另一部分:
               查找姓爲Tang而且名字以字母K開頭的人 精確匹配last_name列而且對
               first_name進行範圍查詢
    
    只訪問索引的查詢:B-tree支持只訪問索引的查詢,不會訪問行
  • B-tree侷限性

B-tree侷限性:(案例中索引順序:last_name first_name dob )

若是查找沒有送索引列的最左邊開始,沒有什麼用處,即不能查找全部叫Kang 的人 
    也不能找到全部出生在某天的人,由於這些列再也不索引最左邊,也不能使用該索引超找
    某個姓氏以特定字符結尾的人
    
    不能跳過索引的列,即不能找到全部姓氏爲Tang而且出生在某個特定日期的人
    若是不定義first_name列的值,Mysql只能使用索引的第一列
    
    存儲引擎不能優化任何在第一個範圍條件右邊的列,好比查詢是where last_name = 'Tang'
    AND first_name like 'K%' AND dob='1993-09-23' 訪問只能使用索引頭兩列
    
    由此可知 索引列順序的重要性!
  • 哈希索引

目前只有Memory存儲引擎支持顯示的哈希索引 並且Memory引擎對我來講不經常使用
    因此咱們就輕描淡寫的過了吧
  • R-tree(空間索引)

Myisam支持空間索引 可使用geometry空間數據類型
    空間索引不會要求where子句使用索引最左前綴能夠全方位索引數據
    能夠高效使用任何數據組合查找 配合使用mercontains()函數使用
  • 全文索引

fulltext是Myisam表特殊索引,從文本中找關鍵字不是直接和索引中的值進行比較
    全文索引能夠和B-Tree索引混用 索引價值互不影響
    全文索引用於match against操做 而不是普通的where子句
  • 前綴索引和索引選擇性

一般索引幾個字符,而不是所有值,以節約空間並獲得好的性能 同時也下降選擇性
    索引選擇性是不重複的索引值和所有行數的比值
    高選擇性的索引有好處,查找匹配過濾更多的行,惟一索引選擇率爲1 最佳狀態
    
    blob列 text列 及很長的varchar列 必須定義前綴索引 mysql 不容許索引他們的全文
  • 前綴索引和索引選擇性實例

造數據
    #複製一份與cs_area表結構
    mysql> create table area like cs_area ;

    #插入1600數據
    mysql> insert into area select * from cs_area limit     1600;

    #模擬真實數據
    mysql> update area set name = (select name from cs_area order by rand() limit 1 );
#表area有name列 須要對name列前綴索引

clipboard.png

#計算得比值接近0.9350就行了

clipboard.png

#分別取 3 4 5位name值計算

clipboard.png

#可知name列添加5位前綴索引就能夠了

clipboard.png

#Mysql不能在order by 或 group by查詢使用前綴索引 也不能將其用做覆蓋索引
  • 彙集索引

彙集索引不是一種單獨的索引類型 而是一種存儲數據的方式
    Innodb 的彙集索引實際上一樣的結構保存了B-tree索引和數據行
    
    "彙集" 是指實際的數據行和相關的鍵值保存在一塊兒 
    每一個表只能有一個彙集索引 所以不能一次把行保存在兩個地方
    
    (因爲彙集索引對我來講 不經常使用 咱們就略過啦~)
  • 覆蓋索引

索引支持高效查找行 mysql也能使用索引來接收列的數據 這樣不用讀取行數據
    
    當發起一個被索引覆蓋的查詢 explain解釋器的extra列看到 using index 

    #知足條件:#
    # select 查詢的字段必須 有索引全覆蓋
    select last_name,first_name 其中 last_name 和first_name 必須都有索引
    #不能在索引執行like操做
  • 爲排序使用索引掃描

mysql排序結果的方式:使用文件排序 、 掃描有序的索引
    explain中的type列若爲 "索引(Index)" 說明mysql掃描索引
    
    單純掃描索引很快,若是mysql沒有使用索引覆蓋查詢 就不得不查找索引中發現的每一行
    
    mysql 能有爲排序和查找行使用一樣的索引
    
    如表 user 索引 (uid,birthday )
    
    使用排序索引:
    .... where date = '1993-09-23' order by uid desc  (索引最左前綴)
    .... where date > '1993-09-23' order by date, uid (兩列索引最左前綴)
    
    不能使用索引進行排序的查詢:
    where date = '1993-09-23' order by uid desc,com_id  
                    (使用了不一樣排序方向,索引都是升序排列)
    where date = '1993-09-23' order by uid desc,staff_id (引用了再也不索引的列)
    where date = '1993-09-23' order by uid (不能造成最左前綴)
    where date > '1993-09-23' order by uid,com_id  
                    (where有範圍條件 所以不會使用餘下索引)
  • 避免多餘和重複索引

重複索引:類型相同,以一樣的順序在一樣的列建立索引 好比在表user id列 添加 unique(id)約束 、id not null
primary key 約束 index(id) 其實這些是相同的索引 !

多餘索引:如存在(A)索引 應該擴展它 知足 (A,B)索引
(A,B)索引 <==> (B)
(A,B)索引 <==> (A)
(A,B) A最左前綴 (B,A) B最左前綴

  • 索引實例研究

設計user表 字段:country、 state/region 、city 、sex 、age 、eye 、color
功能:支持組合條件搜索用戶 支持用戶排序 用戶上次在線時間

  • 支持多種過濾條件

不在選擇性不好的列添加索引

  • 優化排序

select name,gender from user where sex='M' order by rating limit 10000,10

即時有索引 (sex,rating) 高偏移量話費不少時間掃描被丟掉的數據

select name,gender from user inner join (select id from user where x.sex = 'M'
order by rating limit 100000,10) as x using (id)

基於索引(sex,rating) 提取須要行的主鍵列, 聯接以取得全部須要的列


索引和表維護

表維護三個目標:查找和修復損壞、維護精確的索引統計,並減小碎片

  • 查找並修復表損壞

check table 命令 肯定表是否損壞 能抓到大部分表和索引錯誤 repair table 命令修復損壞的表

myisamchk 離線修復工具

  • 更新索引統計

analyze table cs_area 更新索引統計信息 便於優化器優化sql

show index 命令檢查索引的基數性

clipboard.png

  • 減小索引和數據碎片

myisam引擎 使用 optimize table 清除碎片 Innodb 引擎 使用 alter table .. engine =
.. 從新建立索引


正則化和非正則化

  • 正則化和非正則化

正則化數據庫:每一個因素只會表達一次 教師表teacher (id,school_id) 學校表school
(school_id,school_name) 優勢:更新信息只變更一張表 缺點:簡單的學校名稱查詢 須要關聯表
非正則化數據庫:信息是重複的 或者 保存在多個地方

教師表teacher (id,school_id,school_name) 學校表school
(school_id,school_name)

優勢:便於直接統計對應學校名稱的老師 缺點:更新須要變更的表多一張

正則化和非正則化並用:好比須要統計用戶的發帖數 能夠在user表添加字段num_message 保存發帖總數 避免高密度查詢統計

  • 緩存和彙總表

實例:統計過去24小時發佈的信息精確的數量

  • 表週期性建立

週期建立能夠獲得沒有碎片和全排序索引的高效表

clipboard.png

注意此法會將數據清除 只是獲得一個沒有碎片和高效的索引表

計數表:好比緩存用戶朋友數量、文件下載次數 一般創建一個單獨的表 以保持快速維護計數器

計劃任務按期聚合函數查詢 更新對應的字段

相關文章
相關標籤/搜索