mysql查詢優化之索引型別 最左字首

2021-08-30 09:45:44 字數 3747 閱讀 5970

一、什麼是索引?

索引用來快速地尋找那些具有特定值的記錄,所有mysql索引都以b-樹的形式儲存。如果沒有索引,執行查詢時mysql必須從第乙個記錄開始掃瞄整個表的所有記錄,直至找到符合要求的記錄。表裡面的記錄數量越多,這個操作的代價就越高。如果作為搜尋條件的列上已經建立了索引,mysql無需掃瞄任何記錄即可迅速得到目標記錄所在的位置。如果表有 1000個記錄,通過索引查詢記錄至少要比順序掃瞄記錄快100倍。

假設我們建立了乙個名為people的表:

create table people ( peopleid smallint not null, name char(50) not null );

然後,我們完全隨機把1000個不同name值插入到people表。下圖顯示了people表所在資料檔案的一小部分:

可以看到,在資料檔案中name列沒有任何明確的次序。如果我們建立了name列的索引,mysql將在索引中排序name列:

對於索引中的每一項,mysql在內部為它儲存乙個資料檔案中實際記錄所在位置的「指標」。因此,如果我們要查詢name等於「mike」記錄的 peopleid(sql命令為「select peopleid from people where name=\'mike\';」),mysql能夠在name的索引中查詢「mike」值,然後直接轉到資料檔案中相應的行,準確地返回該行的 peopleid(999)。在這個過程中,mysql只需處理乙個行就可以返回結果。如果沒有「name」列的索引,mysql要掃瞄資料檔案中的所有記錄,即1000個記錄!顯然,需要mysql處理的記錄數量越少,則它完成任務的速度就越快。

二、索引的型別

mysql提供多種索引型別供選擇:

* 普通索引

這是最基本的索引型別,而且它沒有唯一性之類的限制。普通索引可以通過以下幾種方式建立:

o 建立索引,例如create index 《索引的名字》 on tablename (列的列表);

o 修改表,例如alter table tablename add index [索引的名字] (列的列表);

o 建立表的時候指定索引,例如create table tablename ( [...], index [索引的名字] (列的列表) );

* 唯一性索引

這種索引和前面的「普通索引」基本相同,但有乙個區別:索引列的所有值都只能出現一次,即必須唯一。唯一性索引可以用以下幾種方式建立:

o 建立索引,例如create unique index 《索引的名字》 on tablename (列的列表);

o 修改表,例如alter table tablename add unique [索引的名字] (列的列表);

o 建立表的時候指定索引,例如create table tablename ( [...], unique [索引的名字] (列的列表) );

* 主鍵

主鍵是一種唯一性索引,但它必須指定為「primary key」。如果你曾經用過auto_increment型別的列,你可能已經熟悉主鍵之類的概念了。主鍵一般在建立表的時候指定,例如「create table tablename ( [...], primary key (列的列表) ); 」。但是,我們也可以通過修改表的方式加入主鍵,例如「alter table tablename add primary key (列的列表); 」。每個表只能有乙個主鍵。

* 全文索引

三、單列索引與多列索引

索引可以是單列索引,也可以是多列索引。下面我們通過具體的例子來說明這兩種索引的區別。假設有這樣乙個people表:

alter table people add index fname_lname_age (firstname,lastname,age);

由於索引檔案以b-樹格式儲存,mysql能夠立即轉到合適的firstname,然後再轉到合適的lastname,最後轉到合適的age。在沒有掃瞄資料檔案任何乙個記錄的情況下,mysql就正確地找出了搜尋的目標記錄!

四、最左字首

多列索引還有另外乙個優點,它通過稱為最左字首(leftmost prefixing)的概念體現出來。繼續考慮前面的例子,現在我們有乙個firstname、lastname、age列上的多列索引,我們稱這個索引為fname_lname_age。當搜尋條件是以下各種列的組合時,mysql將使用fname_lname_age索引:

* firstname,lastname,age

* firstname,lastname

* firstname

從另一方面理解,它相當於我們建立了(firstname,lastname,age)、(firstname,lastname)以及(firstname)這些列組合上的索引。下面這些查詢都能夠使用這個fname_lname_age索引:

table type possible_keys key key_len ref rows extra

people ref fname_lname_age fname_lname_age 102 const,const,const 1 where used

下面我們就來看看這個explain分析結果的含義。

* table:這是表的名字。

* type:連線操作的型別。下面是mysql文件關於ref連線型別的說明:

「對於每一種與另乙個表中記錄的組合,mysql將從當前的表讀取所有帶有匹配索引值的記錄。如果連線操作只使用鍵的最左字首,或者如果鍵不是unique或 primary key型別(換句話說,如果連線操作不能根據鍵值選擇出唯一行),則mysql使用ref連線型別。如果連線操作所用的鍵只匹配少量的記錄,則ref是一種好的連線型別。」

在本例中,由於索引不是unique型別,ref是我們能夠得到的最好連線型別。

如果explain顯示連線型別是「all」,而且你並不想從表裡面選擇出大多數記錄,那麼mysql的操作效率將非常低,因為它要掃瞄整個表。你可以加入更多的索引來解決這個問題。預知更多資訊,請參見mysql的手冊說明。

* possible_keys:

可能可以利用的索引的名字。這裡的索引名字是建立索引時指定的索引暱稱;如果索引沒有暱稱,則預設顯示的是索引中第乙個列的名字(在本例中,它是「firstname」)。預設索引名字的含義往往不是很明顯。

* key:

它顯示了mysql實際使用的索引的名字。如果它為空(或null),則mysql不使用索引。

* key_len:

索引中被使用部分的長度,以位元組計。在本例中,key_len是102,其中firstname佔50位元組,lastname佔50位元組,age佔2位元組。如果mysql只使用索引中的firstname部分,則key_len將是50。

* ref:

它顯示的是列的名字(或單詞「const」),mysql將根據這些列來選擇行。在本例中,mysql根據三個常量選擇行。

* rows:

mysql所認為的它在找到正確的結果之前必須掃瞄的記錄數。顯然,這裡最理想的數字就是1。

* extra:

這裡可能出現許多不同的選項,其中大多數將對查詢產生負面影響。在本例中,mysql只是提醒我們它將用where子句限制搜尋結果集。

七、索引的缺點

到目前為止,我們討論的都是索引的優點。事實上,索引也是有缺點的。

第二,對於需要寫入資料的操作,比如delete、update以及insert操作,索引會降低它們的速度。這是因為mysql不僅要把改動資料寫入資料檔案,而且它還要把這些改動寫入索引檔案。

【結束語】

在大型資料庫中,索引是提高速度的乙個關鍵因素。不管表的結構是多麼簡單,一次500000行的表掃瞄操作無論如何不會快。如果你的**上也有這種大規模的表,那麼你確實應該花些時間去分析可以採用哪些索引,並考慮是否可以改寫查詢以優化應用。

MySQL查詢優化之索引

mysql查詢優化之索引 什麼是索引 索引簡單來說就類似字典,想想我們小時候在中華字典怎麼查某個字。索引的作用就是快速找出在某個列中有一特定值的行。例如 有一張user表,其中有200萬條記錄,記錄著200萬個人的資訊。有乙個phone的字段記錄每個人的 號碼,現在想要查詢出 號碼為 x的人的資訊。...

Mysql索引與優化 之索引型別

一.mysql索引型別可分為 普通索引 index 僅僅加快查詢速度 主鍵索引 primary key 主鍵索引必是唯一,唯一索引不一定是主鍵索引。唯一索引 unique 行上的值不能重複 全文索引 fulltext 二.建立索引 alter table 表名 add index unique fu...

Mysql索引與優化 之索引型別

一.mysql索引型別可分為 普通索引 index 僅僅加快查詢速度 主鍵索引 primary key 主鍵索引必是唯一,唯一索引不一定是主鍵索引。唯一索引 unique 行上的值不能重複 全文索引 fulltext 二.建立索引 alter table 表名 add index unique fu...