性能優化之mysql索引優化


 

sql及索引優化

如何通過慢查詢日志發現有問題的sql?

  1. 查詢次數多且每次查詢占用時間長的sql
    通常為pt-query-digest分析的前幾個查詢

  2. IO大的sql
    注意pt-query-digest分析中的rows examine項

  3. 未命中索引的sql
    注意pt-query-digest分析中rows examine 和 rows send的對比

 

 

 

磁盤IO與預讀:磁盤讀取數據靠的是機械運動,每次讀取數據花費的時間可以分為尋道時間,旋轉時間,傳輸時間三個部分。雖然平常理論上來說沒什么壓力,

但是數據庫如果動輒十萬百萬乃至千萬級數據,顯然是個災難。

 

了解下mysql的B+樹:一種為了減少IO操作快速搜索到數據的數據結構,如下圖:

 


    說明:

        藍色部分磁盤塊

        黃色部分指針

        深藍色目標數據塊
    分析一下查找的過程:

    如果要查詢數據為29的值:

    1.將磁盤一加入到內存中此時發生一次IO,在內存中用二分查找確定29在17和35之間,鎖定磁盤塊1的P2指針

    2.通過磁盤塊1的P2指針的磁盤地址把磁盤塊3由磁盤加載到內存,發生第二次IO

    3. 29在26和30之間,鎖定磁盤塊3的P2指針,通過指針加載磁盤塊8到內存,發生第三次IO,同時內存中做二分查找找到29,結束查詢

    總結:總計三次IO,真實的情況是,3層的b+樹可以表示上百萬的數據,如果上百萬的數據查找只需要三次IO,性能提高將是巨大的,如果沒有索引,

每個數據項都要發生一次IO,那么總共需要百萬次的IO,顯然成本非常非常高。


解釋下什么叫二分法:其實就是一種通過不斷排除不可能的東西,來最終找到需要的東西的一種方法,所以可以理解成排除法。之所以叫二分,是因為

每次排除都把所有的情況分為“可能”和不可能兩種,然后拋棄所有“不可能”的情況。

  

優化sql實際上主要目的是為了減少IO操作:
1.如果想在mysql配置方面減少IO的操作:盡可能使用緩存,減少讀寫對數據庫的隨機IO的請求,同時減少寫的隨機IO的隨時發生,利用各種buffer去緩存。

2.創建索引:合理的索引是為了少量IO操作達到數據的獲取。

  

建立索引的幾大原則:
1.在where 從句,group by從句,on從句中出現的列

2.最左前綴匹配,非常重要的原則,mysql會一直向左匹配直到遇到范圍查詢(>,<,between,like)就停止匹配
eg:a=1 and b=2 and c=3 and d=4   索引  add index (a,b,c,d)  這樣創建d是用不到索引的
eg:a=1 and b=2 and c=3 and d=4   索引  add index(a,b,d,c) 這樣創建則都可以用到,a,b,d的順序可以任意調整

3.離散度大的列放到聯合索引的前面 

    計算離散度的公式是count(distinct col)/count(*),表示字段不重復的比例,比例越大我們掃描的記錄數越少。

    select * from payment where staff_id=2 and customer_id=584;

    是index(sftaff_id,customer_id)好?還是index(customer_id,staff_id)?
    由於customer_id的離散度更大,所以應該使用index(customer_id,staff_id)

4.索引列不能參與計算,保持列干凈
    索引列不能參與計算,保持列干凈,在where語句中索引字段不要使用函數,進行檢索的時候需要把所有元素都應用函數才能比較,先人成本太大。

5.索引字段越小越好
    使用短索引,如果對字符串列進行索引,應該指定一個前綴長度,可節省大量索引空間,提升查詢速度。

6.盡量的擴展索引,不要新建索引。
    

說了這么多索引的優點但是索引也是有負面的:

  1. 每個額外的索引都要占用額外的磁盤空間,並降低寫操作的性能

   2.在修改表的內容時,索引必須進行更新,有時可能需要重構,因此,所花的時間越長。

什么叫做好的索引:

  1. 查詢頻繁(業務邏輯決定)

  2. 區分度高

  3. 長度小(與區分度保持一個平衡就是一個最優的效果)

  4. 盡量能覆蓋常用查詢字段(並不表示所有字段都建立索引)

  5.  

 

sql及索引優化

如何通過慢查詢日志發現有問題的sql?

  1. 查詢次數多且每次查詢占用時間長的sql
    通常為pt-query-digest分析的前幾個查詢

  2. IO大的sql
    注意pt-query-digest分析中的rows examine項

  3. 未命中索引的sql
    注意pt-query-digest分析中rows examine 和 rows send的對比

 

 

 

磁盤IO與預讀:磁盤讀取數據靠的是機械運動,每次讀取數據花費的時間可以分為尋道時間,旋轉時間,傳輸時間三個部分。雖然平常理論上來說沒什么壓力,

但是數據庫如果動輒十萬百萬乃至千萬級數據,顯然是個災難。

 

了解下mysql的B+樹:一種為了減少IO操作快速搜索到數據的數據結構,如下圖:


    說明:

        藍色部分磁盤塊

        黃色部分指針

        深藍色目標數據塊
    分析一下查找的過程:

    如果要查詢數據為29的值:

    1.將磁盤一加入到內存中此時發生一次IO,在內存中用二分查找確定29在17和35之間,鎖定磁盤塊1的P2指針

    2.通過磁盤塊1的P2指針的磁盤地址把磁盤塊3由磁盤加載到內存,發生第二次IO

    3. 29在26和30之間,鎖定磁盤塊3的P2指針,通過指針加載磁盤塊8到內存,發生第三次IO,同時內存中做二分查找找到29,結束查詢

    總結:總計三次IO,真實的情況是,3層的b+樹可以表示上百萬的數據,如果上百萬的數據查找只需要三次IO,性能提高將是巨大的,如果沒有索引,

每個數據項都要發生一次IO,那么總共需要百萬次的IO,顯然成本非常非常高。


解釋下什么叫二分法:其實就是一種通過不斷排除不可能的東西,來最終找到需要的東西的一種方法,所以可以理解成排除法。之所以叫二分,是因為

每次排除都把所有的情況分為“可能”和不可能兩種,然后拋棄所有“不可能”的情況。

  

優化sql實際上主要目的是為了減少IO操作:
1.如果想在mysql配置方面減少IO的操作:盡可能使用緩存,減少讀寫對數據庫的隨機IO的請求,同時減少寫的隨機IO的隨時發生,利用各種buffer去緩存。

2.創建索引:合理的索引是為了少量IO操作達到數據的獲取。

  

建立索引的幾大原則:
1.在where 從句,group by從句,on從句中出現的列

2.最左前綴匹配,非常重要的原則,mysql會一直向左匹配直到遇到范圍查詢(>,<,between,like)就停止匹配
eg:a=1 and b=2 and c=3 and d=4   索引  add index (a,b,c,d)  這樣創建d是用不到索引的
eg:a=1 and b=2 and c=3 and d=4   索引  add index(a,b,d,c) 這樣創建則都可以用到,a,b,d的順序可以任意調整

3.離散度大的列放到聯合索引的前面 

    計算離散度的公式是count(distinct col)/count(*),表示字段不重復的比例,比例越大我們掃描的記錄數越少。

    select * from payment where staff_id=2 and customer_id=584;

    是index(sftaff_id,customer_id)好?還是index(customer_id,staff_id)?
    由於customer_id的離散度更大,所以應該使用index(customer_id,staff_id)

4.索引列不能參與計算,保持列干凈
    索引列不能參與計算,保持列干凈,在where語句中索引字段不要使用函數,進行檢索的時候需要把所有元素都應用函數才能比較,先人成本太大。

5.索引字段越小越好
    使用短索引,如果對字符串列進行索引,應該指定一個前綴長度,可節省大量索引空間,提升查詢速度。

6.盡量的擴展索引,不要新建索引。
    

說了這么多索引的優點但是索引也是有負面的:

  1. 每個額外的索引都要占用額外的磁盤空間,並降低寫操作的性能

   2.在修改表的內容時,索引必須進行更新,有時可能需要重構,因此,所花的時間越長。

什么叫做好的索引:

  1. 查詢頻繁(業務邏輯決定)

  2. 區分度高

  3. 長度小(與區分度保持一個平衡就是一個最優的效果)

  4. 盡量能覆蓋常用查詢字段(並不表示所有字段都建立索引)

  5.  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM