mysql優化-------Myisam與innodb引擎,索引文件的區別


Myisam與innodb引擎,索引文件的區別:
innodb的次索引指向對主鍵的引用。
myisam的次索引和主索引都指向物理行。

myisam一行一行的插入,會產生一行一行的文件,磁盤上有數據文件。
tree樹的值是磁盤上物理位置的指針。

比如加了主鍵索引,索引排成一棵樹的形狀。首先根據id=7在主鍵索引的樹上查找,查找到7之后就知道了7所在的物理行,然后就可以找到id=7的那一行數據了。
還有一個cat_id索引,根據cat_id=15可以找到數據所在的物理行。
所以說myisam的次索引和主索引都指向物理行。

innodb的主鍵索引,數的每一個葉子下面,直接掛在了每行的數據,id=5的地方掛載的就是id=5的這行數據。數據就在葉子上,不用去磁盤上面查找。如果還有其他索引username,username=li的葉子下面放的是id=7.根據username索引這棵樹上找到id=7然后在主鍵樹上找到數據。
所以innodb的次索引指向對主鍵的引用。id的主索引成為聚簇索引,好處是根據主鍵查非常快,壞處是根據其他索引找的時候要多找一次主鍵這棵樹。username是非聚簇索引。

 

innodb的主索引文件上 直接存放該行數據,稱為聚簇索引,次索引指向對主鍵的引用。
myisam中, 主索引和次索引,都指向物理行(磁盤位置)。

注意: innodb來說, 
1: 主鍵索引 既存儲索引值,又在葉子中存儲行的數據
2: 如果沒有主鍵, 則會Unique key做主鍵 
3: 如果沒有unique,則系統生成一個內部的rowid做主鍵.
4: 像innodb中,主鍵的索引結構中,既存儲了主鍵值,又存儲了行數據,這種結構稱為"聚簇索引"


聚簇索引 
優勢: 根據主鍵查詢條目比較少時,不用回行(數據就在主鍵節點下)
劣勢: 如果碰到不規則數據插入時,造成頻繁的頁分裂.

myisam中對於索引文件是要放在內存中緩存起來的。節點會分裂:原來19的節點后來來了15和13,則19的位置換成13,並在下面添加15,19。對於聚簇索引就很嚴重。對於myisam沒什么,對於innodb就很麻煩。

高性能索引策略
對於innodb而言,因為節點下有數據文件,因此節點的分裂將會比較慢.
對於innodb的主鍵,盡量用整型,而且是遞增的整型.
如果是無規律的數據,將會產生的頁的分裂,影響速度.

 

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很快
 
如果用的是myisam,那么都用到了索引覆蓋,應該是一樣都很快,有可能不實用的myisam引擎。myisam無論使用什么索引都是指向物理行的位置。


如果是innodb引擎,每個葉子下面直接放的數據,這些數據比較大內存放不下,就放在磁盤上。innodb的主鍵是聚簇索引。有比較長的列,聚簇索引導致沿id排序時要跨好多塊。而且塊比較多。所以查找很慢。

第二句是聯合索引,聯合索引沒有放數據塊(除了主鍵索引其余索引都指向主鍵索引,不帶數據),而是放的是主鍵索引的位置指向id的值,不帶有數據,文件比較小可以在內存中存放。現在只是取出id不用回行,就是在索引文件中取,而且索引文件比較小就放在內存中,所以很快。第一個語句,也只是在索引文件中查找,發生了索引覆蓋,但是這個主鍵索引文件比較大,而且不一定在內存中,查找主鍵樹的時候來回跳躍就很慢。

如果把數據比較大的字段去掉,速度也會提升,因為查找主鍵索引文件來回跳的時候就不會慢了。

 

 

 

 

通過下面的規律可以看出-----
1: innodb的buffer_page 很強大.
2: 聚簇索引的主鍵值,應盡量是連續增長的值,而不是要是隨機值, (不要用隨機字符串或UUID)
否則會造成大量的頁分裂與頁移動.
實驗: 聚簇索引使用隨機值導致頁頻繁分裂影響速度
過程:建立innodb表, 利用php連接mysql,
分別規則插入10000條數據,不規則插入10000條數據
觀察時間的差異,體會聚簇索引,頁分裂的影響.  


create table t5(
id int primary key,
c1 varchar(500),
c2 varchar(500),
c3 varchar(500),
c4 varchar(500),
c5 varchar(500),
c6 varchar(500)
) engine innodb charset utf8;

create table t6(
id int primary key,
c1 varchar(500),
c2 varchar(500),
c3 varchar(500),
c4 varchar(500),
c5 varchar(500),
c6 varchar(500)
) engine innodb charset utf8;



// testinnodb.php
$time_start = microtime_float();

$str = str_repeat('hello',100);
for($i=1;$i<=10000;$i++) {
   $sql = "insert into t5 values ($i,'$str' , '$str' , '$str' , '$str' , '$str' , '$str'
)";
   //echo $sql;
   mysql_query($sql , $conn);
}

$time_end = microtime_float();
echo 'seq insert cost' , ($time_end - $time_start) , "seconds\n";
function microtime_float()
{
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
}

// rndinnodb.php
$base = range(1,10000);
shuffle($base);

$time_start = microtime_float();
$str = str_repeat('hello',100);
foreach($base as $i) {
   $sql = "insert into t6 values ($i,'$str' , '$str' , '$str' , '$str' , '$str' , '$str'
)";
   //echo $sql;
   mysql_query($sql , $conn);
}

$time_end = microtime_float();
echo 'rand insert cost' , ($time_end - $time_start) , "seconds\n";

function microtime_float()
{
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
}

字段數

混亂程度(步長)

順序1000(秒數)

亂序1000(秒數)

順序寫入page頁數

亂序寫入page

1

1

54.365

53.438

62

91

10

1

53.413

62.940

235

1301

10

100

 

64.18

 

1329

10

1000

 

67.512

 

1325

 

通過上面的規律可以看出-----
1: innodb的buffer_page 很強大.
2: 聚簇索引的主鍵值,應盡量是連續增長的值,而不是要是隨機值, (不要用隨機字符串或UUID)
否則會造成大量的頁分裂與頁移動.

 


免責聲明!

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



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