服务端指南 数据存储篇 | 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。

(完)

更多精彩文章,尽在「服务端思惟」微信公众号!

相关文章
相关标签/搜索