3.1 概括
索引(Index)是数据库中的一种存储结构,用于快速查找数据。索引通常是在数据库表上创建的,可以用于加速查询、排序和数据的唯一性验证。索引可以理解为图书中的目录,通过目录我们可以很快找到页码对应的内容。
当表中有大量数据需要查询时,有两种方式进行检索,一种时全表扫描,另一种就是建立索引。不难想到,全表扫描可以获取到一张表中的所有数据,但缺点就是往往我们都不需要同时使用一张表中的所有数据,也就是说即使我们只需要1到2行数据也要全部扫描,这极大程度占用资源。
常见索引包括如下:
-
B-Tree索引:最常见的索引类型,适用于等值查询和范围查询。B-Tree索引会将索引列的值排序,并将数据分散到不同的叶子节点中。
-
哈希索引:适用于等值查询,不适用于范围查询。哈希索引会将索引列的值通过哈希算法计算出一个哈希值,并将哈希值映射到对应的数据块中。
-
全文索引:适用于文本数据的模糊查询。全文索引会将文本数据拆分成单词,并将单词和对应的文档编号存储在索引中。这里可以对比ES中的倒排索引
3.2 MySQL创建索引
索引也会占用存储空间,并且对于写操作(如插入、更新、删除)会有一定的性能影响。因此,在创建索引时需要根据实际情况进行权衡,避免过度索引导致性能下降。同时创建索引需要耗时,具体看实际情况。
3.2.1 在MySQL数据库中创建B-Tree索引
-- 在表my_table的列my_column上创建B-Tree索引,默认就是B-Tree
CREATE INDEX my_index ON my_table(my_column);
3.2.2 在MySQL数据库中创建哈希索引
需要满足以下条件:
-
被索引的列必须是整数类型或字符串类型。
-
被索引的列必须是固定长度的,例如CHAR或BINARY类型。
因为哈希索引是通过哈希算法计算出一个哈希值,并将哈希值映射到对应的数据块中,所以需要保证被索引的列是固定长度的,以便在计算哈希值时能够准确地进行映射。示例代码如下:
-- 在表my_table的列my_column上创建哈希索引
CREATE INDEX my_index ON my_table(my_column) USING HASH;
使用USIGN 关键字指定索引类型为HASH类型
3.2.3 创建全文索引
在MySQL数据库中创建全文索引需要满足以下条件:
在MySQL数据库中创建全文索引的示例代码如下:
-- 将表my_table的列my_column创建成全文索引
ALTER TABLE my_table ADD FULLTEXT(my_column);
使用全文索引进行查询时,可以使用MATCH AGAINST语句进行查询,例如:
-- 在my_table表中通过my_column列的全文索引进行查询
SELECT * FROM my_table WHERE MATCH(my_column) AGAINST('search_string');
在使用MATCH AGAINST语句进行查询时,可以指定查询的字符串(search_string),MySQL会将查询字符串拆分成多个单词进行匹配,并返回匹配的结果。(分词与模糊查询)
-
被索引的列必须是字符类型,例如CHAR、VARCHAR或TEXT类型。
-
数据库的存储引擎必须是支持全文索引的引擎,例如MyISAM或InnoDB。
3.3 数据库数据结构
在关系型数据库中,索引通常是通过B树、B+树等数据结构实现的,也可以使用哈希表等数据结构。
索引可以提高查询速度的原因是它可以将查询的数据按照某种方式进行排序,并将排序后的结果存储在索引中。当进行查询时,数据库可以通过索引快速定位到符合条件的数据,而不需要遍历整个数据表。例如,如果在一个包含1000万条记录的表中,需要查询某个字段的值是否存在,使用索引可以将查询时间从数秒缩短到毫秒级别。(类比目录与文本内容的关系,索引就是目录)
在创建索引时,需要考虑索引所涉及的列、索引的类型、索引的大小等因素。通常情况下,索引适用于经常被查询但很少修改的列,如主键、外键、查询条件的列等。同时,索引的类型也需要根据具体的查询需求来选择,例如,如果需要在一个范围内进行查询,可以使用B+树索引;如果需要进行精确匹配查询,可以使用哈希索引。此外,索引的大小也需要考虑,过大的索引会占用过多的磁盘空间,而过小的索引则会影响查询性能。
需要注意的是,虽然索引可以提高查询性能,但是过多的索引也会导致数据表的修改性能下降。因此,在创建索引时,需要根据具体的业务场景和数据访问模式来进行选择,避免过多或不必要的索引。
3.4 常见的导致索引失效的关键字
在MySQL数据库中,常见的导致索引失效的关键字如下:
-
NOT:NOT关键字会对查询结果进行反转,这意味着MySQL需要扫描整个表来找到不符合条件的行,而无法使用索引来加速查询。例如:
SELECT * FROM table WHERE NOT column = 'value'
-
LIKE:使用LIKE关键字进行模糊查询时通常需要对查询字符串进行模糊匹配,这需要对表中的每一行进行比较,而无法使用索引来加速查询。例如:
SELECT * FROM table WHERE column LIKE '%value%'
-
OR:OR查询需要对多个条件进行比较,这需要在索引树上进行多次查找,而无法使用单个索引来加速查询。例如:
SELECT * FROM table WHERE column1 = 'value1' OR column2 = 'value2'
-
IS NULL/IS NOT NULL:这些关键字需要对表中的每一行进行比较,所以也无法使用索引来加速查询。例如:
SELECT * FROM table WHERE column IS NULL
虽然这些关键字可能会导致索引失效,但并不是所有情况下都会出现这种情况。具体是否会导致索引失效,还需要根据具体的表结构、索引类型、查询条件等因素来进行具体判断。
3.5 in关键字
使用IN关键字查询时,如果IN子句中的值比较少,MySQL优化器会选择使用索引来加速查询。但是,如果IN子句中的值太多,MySQL优化器可能会选择不使用索引而进行全表扫描,这样会导致索引失效。
具体来说,当IN子句中的值很多时,MySQL优化器可能会认为使用索引比进行全表扫描更慢,因为使用索引需要进行多次索引查找和合并操作。此时,MySQL优化器可能会选择进行全表扫描,因为它可以避免多次索引查找和合并操作,从而提高查询效率。
为了避免IN关键字导致MySQL索引失效,可以考虑以下几种方法:
-
尽量减少IN子句中的值的数量,仅包含必要的值。
-
将IN子句中的值按照索引顺序进行排序,这有助于优化器决定是否使用索引。
-
使用JOIN语句代替IN语句,这样可以避免使用IN关键字,从而避免索引失效的问题。
-
使用EXISTS子查询代替IN子查询,这可以避免使用IN关键字,从而避免索引失效的问题。
以上3,4条都要联系多表查询,个人感觉不是很理解,感觉更麻烦了。