Mysql优化(出自官方文档) - 第八篇(索引优化系列)

Optimization and Indexes

正确的创建索引往往会加快查询速度,但是,没有必要的索引往往只会浪费空间,并且增加插入,更新和删除的开销,因为进行这些操作要同时更新索引。

但是,索引并不是万能的,在下面的几个场景中,索引将会显得不是那么有用:

  • 小表,或者大表,但是需要请求所有行
  • 当一个请求需要表中的大部分行时,连续读往往效率会比索引高,因为连续读会减少磁盘seek的时间。

1 Foreign Key Optimization

如果经常读取一个表中的多个列,那么,把最少访问的列分出来单独作为一个小表,然后使用外键的方式和主表联系起来,这样子在读取数据的时候就能尽量减少磁盘的I/O读写。

2 Column Indexes

  • Index Prefixes

    Mysql允许只使用一些字段的一部分来作为索引,这其中包括所有的TEXTBLOB字段,如下面的例子:

    CREATE TABLE test (blob_col BLOB, INDEX(blob_col(10)));

    需要注意的是,对于CHAR, VARCHAR, TEXT类型的字段,长度为字符个数的意思,但是对于非字符串字段,如BINARY, VARBINARY, BLOB字段,长度为字节个数的意思。

  • FULLTEXT Indexes

    该索引适用于CHAR, VARCHAR, and TEXT的列,并且全文索引不支持前缀,只支持全列的索引。当查询符合如下特征的时候,全文索引将会非常有用:

    • FULLTEXT查询语句值需要document ID或者search rank(分级??)
    • FULLTEXT查询语句对查询到的结果进行一个降序排序,并且有一个LIMIT语句选取top N项,这种情况下为了使用优化必须保证查询语句没有WHEREORDER BY只有一列。
    • FULLTEXT查询只获取COUNT(*)的结果,且没有WHERE语句,如果需要WHERE过滤,请将WHERE写为WHERE MATCH(TEXT) AGAINST('other_text'),并且没有任何> 0的比较操作符。
  • Indexes in the MEMORY Storage Engine

    对于内存存储引擎,默认使用HASH索引,但是同样也支持BTREE索引。

3 Column Indexes && Multiple-Column Indexes

Mysql支持单独的一列作为索引,也可以使用多列作为索引,当使用多列的时候,使用最左边(leftmost prefix of the index)的列进行查询,可以用到索引,否则,Mysql将无法使用索引,举例如下:

假设一个表含有下面的索引:

 INDEX name (last_name,first_name)

对于下面的查询语句都可以使用到name索引:

SELECT * FROM test WHERE last_name='Jones';

SELECT * FROM test
WHERE last_name='Jones'
AND (first_name='John' OR first_name='Jon'); SELECT * FROM test
WHERE last_name='Jones'
AND first_name >='M' AND first_name < 'N';

下面的语句因为没有使用最左边的列进行查询,所以无法使用索引:

SELECT * FROM test WHERE first_name='John';

SELECT * FROM test
WHERE last_name='Jones' OR first_name='John';

假设有两列col1col2,如果索引刚好建在col1col2上,那么可以直接使用索引,但是如果col1col2是单独的索引(即不是多列索引),那么Mysql会尝试使用 Index Merge optimization (see Section 8.2.1.3, “Index Merge Optimization”)技术,或者判断两个索引中哪个的条件是最严苛的,能够排除尽可能的行,在决定使用哪个索引。

4 Comparison of B-Tree and Hash Indexes

  • B-Tree Index Characteristics

    B树索引支持 =, >, >=, <, <=, or BETWEEN操作符,也支持LIKE操作符,但是必须保证LIKE字段不是以通配符开头的。

    如果一个索引没有覆盖所有的AND,那么Mysql将无法使用该索引,换句话说,为了能够使用到该索引,必须保证一个索引的前缀(最左边部分)出现在每一个AND中,举例如下:

    ... WHERE index_part1=1 AND index_part2=2 AND other_column=3
    
        /* index = 1 OR index = 2 */
    ... WHERE index=1 OR A=10 AND index=2 /* optimized like "index_part1='hello'" */
    ... WHERE index_part1='hello' AND index_part3=5 /* Can use index on index1 but not on index2 or index3 */
    ... WHERE index1=1 AND index2=2 OR index1=3 AND index3=3;

    下面的语句将无法使用索引:

        /* index_part1 is not used */
    ... WHERE index_part2=1 AND index_part3=2 /* Index is not used in both parts of the WHERE clause */
    ... WHERE index=1 OR A=10 /* No index spans all rows */
    ... WHERE index_part1=1 OR index_part2=10

    (这里不是很懂?)

    需要注意的是:

    Mysql并不会任何时候都选择使用索引,有的时候,当需要读取特别多的行时,使用索引的效率可能要低于table scan的效率,因为索引会导致磁盘出现更多的寻道消耗,而table scan由于是连续读,则能更大效率的利用磁盘I/O

  • Hash Index Characteristics

    Hash索引相对比于B树索引,可能会出现下面的不同:

    • Hash索引只能用于=或者<=>操作符,不能用于范围查询
    • 优化器无法使用Hash索引来加速ORDER BY操作
    • Mysql无法评估两个value之间有多少行(BETWEEN语句)
    • 只有完整的索引才能正常工作,不能像BTREE那样,使用leftmost prefix key

5 Use of Index Extensions

InnoDB会自动给二级索引增加primary key作为新的索引,这是在内部完成的,用户无法感知,比如下面的表:

CREATE TABLE t1 (
i1 INT NOT NULL DEFAULT 0,
i2 INT NOT NULL DEFAULT 0,
d DATE DEFAULT NULL,
PRIMARY KEY (i1, i2),
INDEX k_d (d)
) ENGINE = InnoDB;

此时,对于索引k_d,其内部真正的实现方式为: (d, i1, i2). 即自动将primary key(i1, i2)添加到k_d后面构成新的二级索引。

这种优化方式,可用于refrangeindex_merge的索引访问场景,Loose Index Scanjoinsort,以及MIN()/MAX()。

比如下面的语句:

SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'

此时由于内部将i1添加到了k_d索引,那么这条语句就可以使用到(d, i1)这样的索引((d, i1)是索引(d, i1, i2)的最左边前缀),由于使用到了更多的列,所以需要扫描的行数将大大减少。

6 Invisible Indexes

这种索引指的是那种真实存在,但是优化器却不会使用的索引,只能对非primary key进行该种设定,其他类型的索引均支持设置为INVISIBLE

例如下面的例子:

CREATE TABLE t1 (
i INT,
j INT,
k INT,
INDEX i_idx (i) INVISIBLE
) ENGINE = InnoDB;
CREATE INDEX j_idx ON t1 (j) INVISIBLE;
ALTER TABLE t1 ADD INDEX k_idx (k) INVISIBLE;

这种索引一般的用途:测试移除一个索引对于性能的影响,因为这种索引不是真正的将其移除了,只是优化器不再考虑该索引,所以并不会对表造成太大的影响。

注意虽然索引是Invisible的,但是这种索引和普通索引一样具有完备的功能,也就是说增删改的时候,Mysql同样会更新Invisible Index,同理,如果在一个非常大的表上创建Invisible Index时,和普通索引一样,开销也是非常巨大的。

7 Descending Indexes

Mysql支持降序索引,不像以前的版本,索引定义里面的DESC不再被忽略,内部对于索引的存储方式也采取降序的方式;而在此之前,Mysql是采用对index进行逆序扫描的方式,当前采用降序的方式效率比以前要高很多。

使用降序索引主要针对下面的场景:

  • 降序索引只支持InnoDB引擎,并且有如下限制:

    • 如果一个二级索引有降序key或者说一个主键包含降序key,那么Mysql无法支持修改Buffering
    • InnoDB的SQL解析器不会使用降序索引,对于full-text查询,这意味着已经被索引的表上面的FTS_DOC_ID 列不能被定义为降序索引。
  • 一个含有降序key的索引无法使用MIN/MAX优化,特指那种含有聚合函数但是却不带GROUP BY的语句。
  • 降序索引只支持BTREE,并不支持HASH索引,降序索引无法支持FULLTEXT或者SPATIAL索引。

Mysql优化(出自官方文档) - 第八篇(索引优化系列)的更多相关文章

  1. Mysql优化(出自官方文档) - 第九篇(优化数据库结构篇)

    目录 Mysql优化(出自官方文档) - 第九篇(优化数据库结构篇) 1 Optimizing Data Size 2 Optimizing MySQL Data Types 3 Optimizing ...

  2. Mysql优化(出自官方文档) - 第二篇

    Mysql优化(出自官方文档) - 第二篇 目录 Mysql优化(出自官方文档) - 第二篇 1 关于Nested Loop Join的相关知识 1.1 相关概念和算法 1.2 一些优化 1 关于Ne ...

  3. Mysql优化(出自官方文档) - 第一篇(SQL优化系列)

    Mysql优化(出自官方文档) - 第一篇 目录 Mysql优化(出自官方文档) - 第一篇 1 WHERE Clause Optimization 2 Range Optimization Skip ...

  4. Mysql优化(出自官方文档) - 第三篇

    目录 Mysql优化(出自官方文档) - 第三篇 1 Multi-Range Read Optimization(MRR) 2 Block Nested-Loop(BNL) and Batched K ...

  5. Mysql优化(出自官方文档) - 第五篇

    目录 Mysql优化(出自官方文档) - 第五篇 1 GROUP BY Optimization 2 DISTINCT Optimization 3 LIMIT Query Optimization ...

  6. Mysql优化(出自官方文档) - 第十二篇(优化锁操作篇)

    Mysql优化(出自官方文档) - 第十二篇(优化锁操作篇) 目录 Mysql优化(出自官方文档) - 第十二篇(优化锁操作篇) 1 Internal Locking Methods Row-Leve ...

  7. Mysql优化(出自官方文档) - 第十篇(优化InnoDB表篇)

    Mysql优化(出自官方文档) - 第十篇(优化InnoDB表篇) 目录 Mysql优化(出自官方文档) - 第十篇(优化InnoDB表篇) 1 Optimizing Storage Layout f ...

  8. Mysql优化(出自官方文档) - 第七篇

    Mysql优化(出自官方文档) - 第七篇 目录 Mysql优化(出自官方文档) - 第七篇 Optimizing Data Change Statements 1 Optimizing INSERT ...

  9. Mysql优化(出自官方文档) - 第六篇

    Mysql优化(出自官方文档) - 第六篇 目录 Mysql优化(出自官方文档) - 第六篇 Optimizing Subqueries, Derived Tables, View Reference ...

随机推荐

  1. free()函数释放一段分配的内存之陷阱

    朋友们对malloc函数应该是比较熟悉了,此函数功能是分配一段内存地址,并且将内存地址给一个指针变量,最后记得再调用free函数释放这段内存地址就可以了,标准的流程对吧,好像没什么问题.但是按照此标准 ...

  2. 小心使用strcpy函数时越界

    strcpy()函数应该是我们用的比较常用的一个函数,基本功能是将一个字符串拷贝到我指定的内存空间.但是要复制的字符串长度超过这段内存空间的话,结果可能是未知的. 比如以下的程序: #include ...

  3. Guid几种格式及之间的互换,以及利用Base64缩短guid的长度到22个字符和还原

    1.Guid.NewGuid().ToString("N") 结果为: 38bddf48f43c48588e0d78761eaa1ce6 2.Guid.NewGuid().ToSt ...

  4. maven install时跳过测试

    xl_echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!! - ...

  5. DataGridView 的使用总结

    一.属性应用 1.设置单元格鼠标点击后就进入编辑状态 设置DataGridView控件的EditMode这个属性,即 EditMode = System.Windows.Forms.DataGridV ...

  6. 关于Hibernate查询对象调用set方法自动同步到数据库解决方案

    Hibernate的get和load方法查询出的实体都是持久化对象,拿到该对象后,如果你调用了该对象的set方法,如果再同一个事务里面,那么在事务递交的时候,Hibernate会把你设置的值自动更新到 ...

  7. 【iOS】no identity found Command /usr/bin/codesign failed with exit code 1

    今天遇到了这个问题,详情如下图: 后来发现是自己脑子短路了……只添加了 Provisioning Profiles, 而忘记添加 Certificates, 就是下面的两个:

  8. tab切换echarts无法正常显示问题

    项目中使用到了Echarts来在展示图表,两个tab切换页面中都存在图表,页面加载完成后 对所有图表进行了初始化和绘制,然后切换查看时,发现图表的宽度不正确.,第一个tab显示是很正常的,但是第二个t ...

  9. 如何确定FPGA电路中DDR4的Speed bin 是否兼容?

    原创 by DeeZeng DDR4 是否兼容,拿更快速度的DDR4,是否可以不改FPGA工程,直接换料就能直接用? 实际工作中,经常会碰到因为DDR3/4 或其他料件换料了,需要判断FPGA工程中I ...

  10. 【POJ - 1862】Stripies (贪心)

    Stripies 直接上中文了 Descriptions 我们的化学生物学家发明了一种新的叫stripies非常神奇的生命.该stripies是透明的无定形变形虫似的生物,生活在果冻状的营养培养基平板 ...