sql及索引優化
如何通過慢查詢日志發現有問題的sql?
-
查詢次數多且每次查詢占用時間長的sql
通常為pt-query-digest分析的前幾個查詢 -
IO大的sql
注意pt-query-digest分析中的rows examine項 -
未命中索引的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.盡量的擴展索引,不要新建索引。
說了這么多索引的優點但是索引也是有負面的:
-
每個額外的索引都要占用額外的磁盤空間,並降低寫操作的性能
2.在修改表的內容時,索引必須進行更新,有時可能需要重構,因此,所花的時間越長。
什么叫做好的索引:
-
查詢頻繁(業務邏輯決定)
-
區分度高
-
長度小(與區分度保持一個平衡就是一個最優的效果)
-
盡量能覆蓋常用查詢字段(並不表示所有字段都建立索引)
-
sql及索引優化
如何通過慢查詢日志發現有問題的sql?
-
查詢次數多且每次查詢占用時間長的sql
通常為pt-query-digest分析的前幾個查詢 -
IO大的sql
注意pt-query-digest分析中的rows examine項 -
未命中索引的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.盡量的擴展索引,不要新建索引。
說了這么多索引的優點但是索引也是有負面的:
-
每個額外的索引都要占用額外的磁盤空間,並降低寫操作的性能
2.在修改表的內容時,索引必須進行更新,有時可能需要重構,因此,所花的時間越長。
什么叫做好的索引:
-
查詢頻繁(業務邏輯決定)
-
區分度高
-
長度小(與區分度保持一個平衡就是一個最優的效果)
-
盡量能覆蓋常用查詢字段(並不表示所有字段都建立索引)
-