如何預估索引性能?

在《DB——數據的讀取和存儲方式》中,咱們介紹了影響數據讀取的方式,隨機IO和順序IO,在《Sql優化器究竟幫你作了哪些工做?》介紹了影響查詢的一些基本因素,其中介紹了過濾因子、索引片的寬窄與大小以及匹配列和過濾列 是如何應用在sql查詢中的。在《什麼是三星索引》介紹了索引設計須要主要的因素以及推薦的設計方式。算法

那麼這篇,咱們將綜合運用這些知識,並經過兩個方法,快速估算當前的索引的性能,以及查詢的效率。從這篇文章你會獲得如下知識:BQ—基本問題法QUBE—快速上限估算法sql

table:數據庫

CREATE TABLE `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(100) DEFAULT NULL,
  `sex` int(11) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `c_date` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  # 索引
  KEY `id_name_sex` (`id`,`user_name`,`sex`),
  KEY `name_sex_age` (`user_name`,`sex`,`age`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
​

 

1、基本問題法—BQ

基本問題法,這個方法想必會用數據庫的人,都會知道,簡單來說,就是當前select 是否用到了索引,不過BQ方式會更加詳盡。緩存

評估的方式併發

現有的索引或者計劃中的索引是否包含了 WHERE 中使用的所有列,也就是當前查詢,是否有一個索引是半寬索引(匹配where後全部謂詞列)? 若是沒有,那麼應該將缺乏的謂詞列加到現有索引上。性能

 

基於前面介紹的知識,咱們能夠知道,半寬索引能夠確保回表訪問只發生在全部查詢條件都知足的時候。也就是說,條件過濾會在表掃描以前發生,而不是以後發生。雖然不能避免主表的隨機訪問,但起碼能夠支持索引表的順序讀取。優化

不過對於BQ並不能保證足夠的性能。好比以下:spa

上述中where後面的謂詞都包含在索引(name,sex,age),但這個查詢倒是一個全索引或者全表掃描,三星中一個都不佔有。具體緣由,能夠查看《Sql優化器究竟幫你作了哪些工做?》中的介紹。.net

那麼有沒有更全面的評估方式?下面的QUBE,就是一種更全面快速的評估方式。設計

 

2、快速估算上限法——QUBE

QUBE比BQ更耗時,但它能揭示全部與索引或者表設計相關的性能問題。QUBE會對每一個謂詞所用的過濾因子都很是接近於實際的最差狀況,如此雖然會比較悲觀,但不會像BQ那樣漏掉髮現的某些問題。

QUBE的目的在於在開發期間就能將訪問路徑緩慢的問題暴露出來,這個估算方法的輸出就是本地響應時間(Local Response Time),簡稱爲LRT。

咱們先大概瞭解一下LRT的時間組成。在一個常規的多用戶環境中,程序的併發會致使對所需資源的各類競爭,所以不得不排隊來獲取這些資源。那麼QUBE會忽略磁盤驅動排隊之外的其餘全部類型的排隊,已提供一個簡單的評估過程。

在排除以上因素以後,咱們獲得的一個是一個很是簡單的估算過程,僅須要如下變量來處理便可。

最終的QUBE公式爲:

LRT=TR * 10ms + TS * 0.01ms + F * 0.1ms

 

咱們把隨機訪問一次的時間定義爲10ms,以及把順序讀取一次的時間定義爲0.01ms,這個在《DB——數據的讀取和存儲方式》有介紹,不瞭解的能夠過去看一下。

 

3、示例

咱們假設表test有1000w的數據,同時又以下兩個索引,一個是聯合主鍵,一個是輔助索引:

聯合主鍵:PRIMARY KEY (id,user_name,sex)

輔助索引:KEY name_sex_age (user_name,sex,age)

 

一、示例1—輔助索引訪問

select user_name,sex,age,c_date from test where user_name=’test1’ and sex=1

匹配列user_name sex

匹配索引name_sex_age (user_name,sex,age),

 

過濾因子:

其中user_name 有500個不一樣的值,過濾因子爲0.2%(1/500)

其中sex 有2個不一樣的值,過濾因子爲50%(1/2)

組合過濾因子=0.2% * 50% =0.1%結果集=1000w * 0.2% * 50% =10000

LRT估算:

一、訪問索引表

該查詢匹配到了索引name_sex_age (user_name,sex,age),過濾因子是0.1%,其須要掃描索引表數據,是10000行,這其中包含1次隨機查詢(第一次定位page)和9999次順序查詢。

索引LRT:

TR =1 * 10ms=10ms

TS=9999 * 0.01ms=100ms

index_LRT=10ms+100ms=110ms

 

二、訪問主表

由於該索引name_sex_age (user_name,sex,age)是一個輔助索引,而字段’c_date’ 並不在索引中,所以須要一次主表掃描。而此索引不是聚簇索引,因此回表查詢,須要10000次的隨機IO查詢。

表LRT:

TR=10000 *10ms=100000ms

TS=0 *  0.01ms=0ms

LRT=100000ms+0ms=100000ms

 

三、LRT 總耗時

Fetch =10000*0.1ms=1000ms

LRT =索引LRT+表LRT+Fetch=110ms+100000ms+1000ms=101110ms=101s

上述查詢咱們大概估算出的查詢時間爲101s左右,真實狀況由於磁盤緩存以及表預讀取的緣由,速度會比這個快。不過咱們不考慮這些,我能夠經過這個值的預估,瞭解到當前查詢以及索引的性能,以供本身判斷和優化。

四、改善&優化

上述查詢中,咱們能夠看到耗時最多的地方,發生在主表回查中,緣由是字段’c_date’ 不在輔助索引name_sex_age 中,形成了過多的隨機訪問。

咱們能夠在索引中增長匹配字段(user_name,sex,agec_date) ,如此就能夠直接索引表訪問,再也不進行回表訪問。咱們能夠看到 此時的索引是一個三星索引。如此能夠節省100000ms,只剩下1020ms左右。

 

二、示例2—聚簇索引訪問

select user_name,sex,age,c_date from test where user_name='test1' and sex=1 and id between 1000 and 101000;

匹配列id

過濾列user_name sex

匹配索引 PRIMARY KEY (id,user_name,sex)

 

過濾因子

id between 1000 and 101000,有100000行數據。

user_name 有500個不一樣的值,過濾因子爲0.2%(1/500)

sex 有2個不一樣的值,過濾因子爲50%(1/2)

組合過濾因子=0.2% * 50% =0.1%

結果集=10w * 0.2% * 50% =100

 

LRT估算:

因爲咱們此次應用的索引是主鍵索引(也就是聚餐索引(引擎innodb)),因此個人表LRT訪問 時候,是順序訪問,不是隨機IO訪問。

LRT =索引LRT+表LRT+Fetch=11ms+11ms+10ms=31ms

相關文章
相關標籤/搜索