1. 程式人生 > >MySQL索引優化策略-論壇經典例項整理

MySQL索引優化策略-論壇經典例項整理

二.索引優化策略

索引型別

1.B-tree索引

注:名叫btree索引,大的方面看,都用的平衡樹,但具體的實現上,各引擎稍有不同。比如嚴格的說NDB引擎使用的是T-tree

Myisam,innodb中預設用B-tree索引

B-tree系統抽象一下,可以理解為“排好序的快速查詢結構”

B-tree常見誤區:

1.     在where條件常用的列上都加上索引

例:where cat_id=3and price>100  cat_id和price上都加上索引,只能用上cat_id和price索引其中一個; 因為是獨立的索引,同時只能用上一個

 2.在多列上建立索引後,索引發揮作用,需要滿足左字首規則

myisam主索引和次索引都指向物理行(磁碟位置),稱為非聚簇索引

InnoDB主索引檔案上,直接存放該行資料,稱為聚簇索引,次索引指向對主鍵的引用

注意:innodb來說:

1.     主鍵索引既儲存索引值,又在葉子中儲存行的資料

2.     如果沒有主鍵(primary key),則會unique key做主鍵

3.     如果沒有unique,則系統生成一個內部的rowid做主鍵

4.     像innodb中,主鍵的索引結構,既儲存了主鍵值,又儲存了行資料,這種結構稱為“聚簇索引”

 

單獨兩個列的獨立索引and查詢,只能一個發揮作用,更多使用的是多列索引

多列索引的考慮因素—列的查詢頻率,列的區分度,列的查詢順序。注意一定要結合實際業務場景

索引與排序

1.     對於覆蓋索引,直接在索引上查詢時,就是有序的 using index

在innodb引擎中,沿著索引欄位排序,也是自然有序的;對於myisam引擎,如果按某索引欄位排序,如id 但取出的欄位中,有未索引欄位,如goods_name,myisam的做法不是索引->回行,索引->回行,而是先取出所有行,再進行排序

2.先取出資料,形成臨時表做filesort(檔案排序,但檔案可能在磁碟上,也可能在記憶體中)

索引提高排序(照著有序的索引找出來的資料自然是有序的)

索引用於分組(分組需要先按分組欄位排序),group by的列要有索引,可以避免臨時表及檔案排序

order by的列要和group by的列一致,否則也會引起臨時表

(原因是因為group by和orderby都需要排序,所以如果兩者的列不一致,那必須經過至少一次排序)

索引覆蓋

       索引覆蓋是指如果查詢的列恰好是索引的一部分,那麼查詢只需要在索引檔案上進行,不需要回行到磁碟再找資料

       這種查詢速度非常快,稱為“索引覆蓋”

聚簇索引的頁分裂

聚簇索引中,N行形成一個頁,當不規則插入時,不斷造成頁分裂,插入速度比較慢

冗餘索引:

冗餘索引是指2個索引所覆蓋的列有重疊,稱為冗餘索引

例:文章標籤表id  artid  tag

       實際使用中有兩種查詢:artid—查詢文章的—tag    tag—查詢文章的--artid

例題

1.有商品表,有主鍵goods_id,欄目列cat_id,價格price,在價格列上已經加了索引,單價格查詢還是很慢。

可能原因,怎麼解決?

       實際場景中,一個電商網站商品的分類很多,直接在所有商品中按價格查詢商品是極少的,一般客戶都來到分類下,再查;

可能在商品欄目列上已經加了一個索引,導致price上加的索引沒發揮作用;

改正:去掉單獨的price列的索引,加(cat_id, price)複合索引。

2.假設某個表有一個聯合索引(c1,c2,c3,c4) 以下 只能使用該聯合索引的c1,c2,c3部分

A. where c1 = ‘a’ and c2 = ‘b’ and c4>’c’ and c3 = ‘d’
B. where c1 = ‘a’ and c2 = ‘b’ and c4=’c’ order by c3
C. where c1 = ‘a’ and c4 = ‘b’ group by c3, c2
D. where c1 = ‘a’ and c5 = ‘b’ order by c2, c3
E. where c1 = ‘a’ and c2 = ‘b’ and c5=’c’ order by c2, c3
create table t6(
    c1 char(1) not null default '',
    c2 char(1) not null default '',
    c3 char(1) not null default '',
    c4 char(1) not null default '',
    c5 char(1) not null default '',
    key idx_t6(c1,c2,c3,c4)
)engine myisam charset=utf8;
insert into t6 values ('a','b','c','d','e'),('A','b','c','d','e'),('a','B','c','d','e');

詳見:https://www.cnblogs.com/loveyouyou616/p/6369744.html

3. 問題描述如下:

create table A(

id varchar(64) primary key,

ver int,

)

在id, ver上有聯合索引

10000條資料

為什麼select id from A order by id特別慢?

而select id from A order by id, ver非常快

我們表有幾個很長的欄位 text(3000)

       疑問:id, (id, ver)都有索引,select id都應該產生“索引覆蓋“的效果,為什麼前者慢,後者快

       思路:innodb聚簇與myisam非聚簇索引的不同,索引覆蓋這兩個角度來考慮

       分析:對於myisam索引都是指向磁碟上的位置(索引不儲存其他列的資料,統統指到磁碟去)

推斷:

1.     表如果是myisam引擎,2個語句速度不會有明顯差異

2.     Innodb表因為聚簇索引,id主鍵索引要在磁碟上跨N多塊,導致速度慢

3.     即使innodb引擎,如果沒有那幾個varbinary長列,2個語句的速度也不會有明顯差異

2.hash索引

在memory裡預設是hash索引,hash的理論查詢時間複雜度為O(1)

Hash查詢如此高效,為什麼不都用hash索引?

1.     hash函式計算後的結果是隨機的;如果是在磁碟上放置資料。

比如:主鍵id為例,隨著id增長,id對應的行,在磁碟上隨機放置

2.無法對範圍查詢進行優化

3.無法利用字首索引;比如:field列的值為“helloworld”,並加索引,hash(“helloworld”)和hash(“hello”),兩者的關係仍為隨機

4.排序也無法優化

5.必須回行;也就是說,通過索引拿到資料位置,必須回到表中取資料

注:hash演算法返回一個地址,資料和hash值是一對一算出來。位置重複:拉鍊演算法

理想的索引

1.     查詢頻繁  2.區分度高  3.長度小  4.儘量能覆蓋常用查詢欄位

索引長度直接影響索引檔案的大小,影響增刪改的速度,並間接影響查詢速度(佔用記憶體多)

索引碎片與維護

在長期的資料更新過程中,索引檔案和資料檔案,都將產生空洞,形成碎片

我們可以通過一個nop操作(不產生對資料實質影響的操作), 來修改表

比如: 表的引擎為innodb , 可以alter table xxx engine innodb (修改表的引擎型別為其預設型別會重新調整資料,但不會影響資料)

optimize table 表名 ,也可以修復

注意: 修復表的資料及索引碎片,就會把所有的資料檔案重新整理一遍,使之對齊.

這個過程,如果表的行數比較大,也是非常耗費資源的操作.

所以,不能頻繁的修復.

如果表的Update操作很頻率,可以按周/月,來修復.

如果不頻繁,可以更長的週期來做修復.

詳見:https://www.cnblogs.com/qlqwjy/p/8594859.html