服務端指南 資料儲存篇 | MySQL(03) 如何設計索引

樑桂釗發表於2017-04-12

改善效能最好的方式,就是通過資料庫中合理地使用索引,換句話說,索引是提高 MySQL 資料庫查詢效能的主要手段。在下面的章節中,介紹了索引型別、強制索引、全文索引。

原文地址:服務端指南 資料儲存篇 | MySQL(03) 如何設計索引
部落格地址:blog.720ui.com/

基本索引型別

MySQL 索引可以分為單列索引、複合索引、唯一索引、主鍵索引等。這裡,將為讀者介紹這幾種索引的特點。

單列索引

單列索引:單列索引是最基本的索引,它沒有任何限制。

建立一個單列索引,例如:

create index index_name on tbl_name(index_col_name);複製程式碼

同時,也可以通過修改表結構的方式新增索引,例如:

alter table tbl_name add index index_name on (index_col_name);複製程式碼

複合索引

複合索引:複合索引是在多個欄位上建立的索引。複合索引遵守“最左字首”原則,即在查詢條件中使用了複合索引的第一個欄位,索引才會被使用。因此,在複合索引中索引列的順序至關重要。

建立一個複合索引,例如:

create index index_name on tbl_name(index_col_name,...);複製程式碼

同時,也可以通過修改表結構的方式新增索引,例如:

alter table tbl_name add index index_name on (index_col_name,...);複製程式碼

唯一索引

唯一索引:唯一索引和單列索引類似,主要的區別在於,唯一索引限制列的值必須唯一,但允許有空值。對於多個欄位,唯一索引規定列值的組合必須唯一。

建立一個複合索引,例如:

create unique index index_name on tbl_name(index_col_name,...);複製程式碼

同時,也可以通過修改表結構的方式新增索引,例如:

alter table tbl_name add unique index index_name on (index_col_name,...);複製程式碼

主鍵索引

主鍵索引:主鍵索引是一種特殊的唯一索引,不允許有空值。此外, CREATE INDEX 不能建立主鍵索引,需要使用 ALTER TABLE 代替,例如:

alter table tbl_name add primary key(index_col_name);複製程式碼

強制索引

有時,因為使用 MySQL 的優化器機制,原本應該使用索引的優化器,反而選擇執行全表掃描或者執行的不是預期的索引。此時,可以通過強制索引的方式引導優化器採取正確的執行計劃。

使用強制索引,SQL 語句只使用建立在 index_col_name 上的索引,而不使用其它的索引。

select * from tbl_name force index (index_col_name) …複製程式碼

切記,不要濫用強制索引,因為 MySQL 的優化器會同時評估 I/O 和 CPU 的成本,一般情況下,可以自動分析選擇最合適的索引。

如果優化器成本評估錯誤,因而沒有選擇最佳方案,最好的方法應該是將合適的索引修改得更好。

如果某個 SQL 語句使用強制索引,需要在系統迭代開發過程中時時維護強制索引,一方面,需要保證使用的強制索引最優,另外一面,需要保證所使用的強制索引不能被誤刪,不然將導致 SQL 報錯。

因此,如果某個 SQL 語句必須要使用強制索引,建議在團隊內部開展嚴格地評審後才可以使用。

全文索引

在一般情況下,模糊查詢都是通過 like 的方式進行查詢。但是,對於海量資料,這並不是一個好辦法,在 like "value%" 可以使用索引,但是對於 like "%value%" 這樣的方式,執行全表查詢,這在資料量小的表,不存在效能問題,但是對於海量資料,全表掃描是非常可怕的事情,所以 like 進行模糊匹配效能很差。

這種情況下,需要考慮使用全文搜尋的方式進行優化。全文搜尋在 MySQL 中是一個 FULLTEXT 型別索引。 FULLTEXT 索引在 MySQL 5.6 版本之後支援 InnoDB,而之前的版本只支援 MyISAM 表。

假設,有一張應用全文索引表。

CREATE TABLE IF NOT EXISTS `app_full_text` (
  `app_id` bigint(20) NOT NULL,
  `app_name_full_text` text NOT NULL,
  `introduce_full_text` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;複製程式碼

現在需要對應用的名稱建立全文索引,可以這麼設計。

alter table `app_full_text` add fulltext key `app_name_intro` (`app_name_full_text`);複製程式碼

預設 MySQL 不支援中文全文檢索,對此,網上的方案很多,例如新增 MySQL 擴充套件,或者將內容轉換成拼音的方式儲存在索引表,或者使用 IKAnalyzer 分詞庫等,其效果都不是非常的理想。使用拼音分詞,雖然可以查詢到內容,但是如果拼音相同的情況,是非常致命的,而且分詞的粒度也是個很可怕的問題。使用 IKAnalyzer 分詞庫,效果也不是很好。因為業務的需要,命中率也是非常重要的,有的關鍵字沒有進行分詞導致查詢不到的問題。

我之前的臨時解決方案。如下:

  • 為中文內容表提供一個全文索引表,儲存全文索引分詞資訊,兩張表根據中文內容表的 ID 進行關聯。
  • 將內容進行分詞後,用 base64 編碼,儲存在全文索引表中。
  • 關鍵的一步,如何分詞,分詞的命中率問題。很簡單,自定義分詞庫,寫一個分詞演算法將所有的組合進行分詞,在內容不多的情況下非常有用。舉個例子,“樑桂釗”,可以進行自定義分詞:[樑、桂、釗、樑桂、桂釗、樑桂釗]。

事實上,MySQL 全文搜尋只是一個臨時方案,對於全文搜尋場景,更專業的做法是使用全文搜尋引擎,例如 ElasticSearch 或 Solr。

(完)

更多精彩文章,盡在「服務端思維」微信公眾號!

服務端指南 資料儲存篇 | MySQL(03) 如何設計索引

相關文章