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

改善性能最好的方式,就是經過數據庫中合理地使用索引,換句話說,索引是提升 MySQL 數據庫查詢性能的主要手段。在下面的章節中,介紹了索引類型、強制索引、全文索引。javascript

原文地址:服務端指南 數據存儲篇 | MySQL(03) 如何設計索引
博客地址:blog.720ui.com/java

基本索引類型

MySQL 索引能夠分爲單列索引、複合索引、惟一索引、主鍵索引等。這裏,將爲讀者介紹這幾種索引的特色。mysql

單列索引

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

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

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

同時,也能夠經過修改表結構的方式添加索引,例如:數據庫

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

複合索引

複合索引:複合索引是在多個字段上建立的索引。複合索引遵照「最左前綴」原則,即在查詢條件中使用了複合索引的第一個字段,索引纔會被使用。所以,在複合索引中索引列的順序相當重要。微信

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

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。

(完)

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

相關文章
相關標籤/搜索