MySQL如何使用索引

本文详细解析了MySQL中索引的使用方式,包括多列索引的前缀特性、LIKE语句的索引使用条件、全文索引的适用场景、IS NULL的索引优化以及可能导致索引失效的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MySQL如何使用索引?
看 这篇文章前,先看通过 EXPLAIN 分析低效 SQL的执行计划

索引用于快速找出在某个列中有一特定值的行。对相关列使用索引是提高 SELECT 操作 性能的最佳途径。 查询要使用索引最主要的条件是查询条件中需要使用索引关键字,如果是多列索引,那 么只有查询条件使用了多列关键字最左边的前缀时,才可以使用索引,否则将不能使用索引。

1.使用索引
在 MySQL 中,下列几种情况下有可能使用到索引。 (1)对于创建的多列索引,只要查询的条件中用到了最左边的列,索引一般就会被使用, 举例说明如下。 首先按company_id,moneys的顺序创建一个复合索引,具体如下:

mysql> create index ind_sales2_companyid_moneys on sales2(company_id,moneys); 
Query OK, 1000 rows affected (0.03 sec) 
Records: 1000  Duplicates: 0  Warnings: 0 

然后按company_id 进行表查询,具体如下: mysql> explain select * from sales2 where company_id = 2006\G;
*************************** 1. row ***************************

        id: 1 
  select_type: SIMPLE 
        table: sales2 
         type: ref 
possible_keys: ind_sales2_companyid_moneys 
          key: ind_sales2_companyid_moneys 
      key_len: 5 
          ref: const 
         rows: 1 
        Extra: Using where 

1 row in set (0.00 sec) 可以发现即便 where 条件中不是用的company_id与moneys 的组合条件,索引仍然能 用到,这就是索引的前缀特性。但是如果只按 moneys 条件查询表,那么索引就不会 被用到,具体如下: mysql> explain select * from sales2 where moneys = 1\G;
*************************** 1. row ***************************

       id: 1 
  select_type: SIMPLE 
        table: sales2 
         type: ALL 
possible_keys: NULL 
          key: NULL 
      key_len: NULL 
          ref: NULL 
         rows: 1000 
        Extra: Using where 

1 row in set (0.00 sec) (2)对于使用 like 的查询,后面如果是常量并且只有%号不在第一个字符,索引才可能会 被使用,来看下面两个执行计划: mysql> explain select * from company2 where name like '%3'\G;
*************************** 1. row ***************************

      id: 1 
  select_type: SIMPLE 
        table: company2 
         type: ALL 
possible_keys: NULL 
          key: NULL 
      key_len: NULL 
          ref: NULL 
         rows: 1000 
        Extra: Using where 
1 row in set (0.00 sec) 
mysql> explain select * from company2 where name like '3%'\G; 

*************************** 1. row ***************************

       id: 1 
  select_type: SIMPLE 
        table: company2 
         type: range 
210 
 
possible_keys: ind_company2_name 
          key: ind_company2_name 
      key_len: 11 
          ref: NULL 
         rows: 103 
        Extra: Using where 

1 row in set (0.00 sec) 可以发现第一个例子没有使用索引,而第二例子就能够使用索引,区别就在于“%”的位置 不同,前者把“%”放到第一位就不能用到索引,而后者没有放到第一位就使用了索引。 另外,如果如果 like 后面跟的是一个列的名字,那么索引也不会被使用。 (3)如果对大的文本进行搜索,使用全文索引而不用使用 like ‘%…%’。 (4)如果列名是索引,使用 column_name is null 将使用索引。如下例中查询 name 为 null 的记录就用到了索引: mysql> explain select * from company2 where name is null\G;
*************************** 1. row ***************************

        id: 1 
  select_type: SIMPLE 
        table: company2 
         type: ref 
possible_keys: ind_company2_name 
          key: ind_company2_name 
      key_len: 11 
          ref: const 
         rows: 1 
        Extra: Using where 
1 row in set (0.00 sec) 

2.存在索引但不使用索引
在下列情况下,虽然存在索引,但是 MySQL 并不会使用相应的索引。 (1) 如果 MySQL 估计使用索引比全表扫描更慢,则不使用索引。例如如果列 key_part1 均匀分布在 1 和 100 之间,下列查询中使用索引就不是很好: SELECT * FROM table_name where key_part1 > 1 and key_part1 < 90; (2) 如果使用 MEMORY/HEAP 表并且 where 条件中不使用“=”进行索引列,那么 不会用到索引。heap 表只有在“=”的条件下才会使用索引。 (3) 用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引, 那么涉及到的索引都不会被用到,例如: mysql> show index from sales\G;
*************************** 1. row ***************************

    Table: sales 
  Non_unique: 1 
    Key_name: ind_sales_year 
Seq_in_index: 1 
 Column_name: year 
211 
 
   Collation: A 
 Cardinality: NULL 
    Sub_part: NULL 
      Packed: NULL 
        Null:  
  Index_type: BTREE 
     Comment:  

1 row in set (0.00 sec) 从上面可以发现只有 year 列上面有索引,来看如下的执行计划: mysql> explain select * from sales where year = 2001 or country = 'China'\G;
*************************** 1. row ***************************

      id: 1 
  select_type: SIMPLE 
        table: sales 
         type: ALL 
possible_keys: ind_sales_year 
          key: NULL 
      key_len: NULL 
          ref: NULL 
         rows: 12 
        Extra: Using where 

1 row in set (0.00 sec) 可见虽然在year这个列上存在索引ind_sales_year,但是这个SQL语句并没有用到这个索引, 原因就是 or 中有一个条件中的列没有索引。 (4) 如果不是索引列的第一部分,如下例子: mysql> explain select * from sales2 where moneys = 1\G;
*************************** 1. row ***************************

        id: 1 
  select_type: SIMPLE 
        table: sales2 
         type: ALL 
possible_keys: NULL 
          key: NULL 
      key_len: NULL 
          ref: NULL 
         rows: 1000 
        Extra: Using where 1 row in set (0.00 sec)

可见虽然在 money 上面建有复合索引,但是由于 money 不是索引的第一列,那么在查询中 这个索引也不会被 MySQL 采用。 (5) 如果 like 是以%开始,例如: mysql> explain select * from company2 where name like '%3'\G;
*************************** 1. row ***************************

         id: 1 

 
  select_type: SIMPLE 
        table: company2 
         type: ALL 
possible_keys: NULL 
          key: NULL 
      key_len: NULL 
          ref: NULL 
         rows: 1000 
        Extra: Using where 1 row in set (0.00 sec)

可见虽然在 name 上建有索引,但是由于 where 条件中 like 的值的“%”在第一位了,那么 MySQL 也不会采用这个索引。 (6) 如果列类型是字符串,那么一定记得在 where 条件中把字符常量值用引号引 起来,否则的话即便这个列上有索引,MySQL 也不会用到的,因为,MySQL 默认把输入的 常量值进行转换以后才进行检索。如下面的例子中company2表中的name字段是字符型的, 但是 SQL 语句中的条件值 294 是一个数值型值,因此即便在 name 上有索引,MySQL 也不能 正确地用上索引,而是继续进行全表扫描。 mysql> explain select * from company2 where name = 294\G;
*************************** 1. row ***************************

      id: 1 
  select_type: SIMPLE 
        table: company2 
         type: ALL 
possible_keys: ind_company2_name 
          key: NULL 
      key_len: NULL 
          ref: NULL 
         rows: 1000 
        Extra: Using where 
1 row in set (0.00 sec) 
mysql> explain select * from company2 where name = '294'\G; 

*************************** 1. row ***************************

       id: 1 
  select_type: SIMPLE 
        table: company2 
         type: ref 
possible_keys: ind_company2_name 
          key: ind_company2_name 
      key_len: 23 
          ref: const 
         rows: 1 
        Extra: Using where 
1 row in set (0.00 sec) 
 

从上面的例子中可以看到,第一个 SQL 语句中把一个数值型常量赋值给了一个字符型的列 name,那么虽然在 name 列上有索引,但是也没有用到;而第二个 SQL 语句就可以正确使 用索引

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术砖家--Felix

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值