【问题标题】:Best way to create Database index on MySQL在 MySQL 上创建数据库索引的最佳方法
【发布时间】:2026-02-15 11:45:01
【问题描述】:

我想通过多个属性的组合来搜索我的 MYSQL 数据库表,我想索引它。例如,如果这是我的桌子:

+----+--------+--------+--------+--------+
| id | field1 | field2 | field3 | field4 |
+----+--------+--------+--------+--------+
|    |        |        |        |        |

我想运行这样的查询:

select * from table where field1=value1 and field2=value2;
select * from table where field3=value3 and field4=value4;
select * from table where field1=value1 and field2=value2 and field3=value3;
select * from table where field4=value4;

为类似的东西创建索引的最佳方法是什么?

CREATE INDEX my_index on table(field1, field2, field3, field4); 

或类似的东西:

CREATE INDEX my_index1 on table(field1); 
CREATE INDEX my_index2 on table(field2); 
CREATE INDEX my_index3 on table(field3); 
CREATE INDEX my_index4 on table(field4); 

还是完全不同的东西?

【问题讨论】:

  • 我想说的每个字段的索引
  • 这个问题非常笼统,因此很难回答。作为一般经验法则,您应该根据要运行的查询、运行它们的频率以及它们对工作负载的影响来索引列。您甚至可以添加一些仅用于索引目的的列,没有语义价值。您还应该考虑到数据库和查询结构的未来变化。
  • "我会说的每个字段的索引" @krishKM 不,这将被称为 index shot gunningindex shotgun
  • 要添加到@Pyromonk 索引选择性也很重要,您应该知道优化器是基于成本的。如果需要或需要检查表中的 90%,MySQL 不使用索引。 . 事实上,使用索引会比全表扫描更昂贵.. 更多随机磁盘 I/O 请求与一个随机磁盘 I/O 请求和“流”(读取)完整表并过滤掉您的记录不需要在EXPLAIN 输出中的额外列中使用“使用位置”将表明这一点。
  • 您在 every 过滤器中是否使用了任何列?有没有你不经常使用的?每列的数据熵如何?

标签: mysql database indexing


【解决方案1】:

根据您要使用的查询类型,我会说最推荐的创建索引的方法是:

CREATE INDEX my_index1 on table(field1); 
CREATE INDEX my_index2 on table(field2); 
CREATE INDEX my_index3 on table(field3); 
CREATE INDEX my_index4 on table(field4); 

然后你将创建4个可以独立使用的不同索引,否则你将创建一个复合索引。

为什么一个索引在这里不起作用?

因为只有一个包含多个字段的索引,如果您严格使用从左到右的查询字段,您的查询只会应用索引。我举了一些例子:

EXPLAIN SELECT * FROM table WHERE field2=value2 AND field1=value1;

此查询将为字段field1field2 应用索引。为什么?因为您使用的是已创建索引中最左侧的两个字段。

您可以在explain 字段possible_keys 上看到它,其值为my_index

但是下一个例子:

EXPLAIN SELECT * FROM table WHERE field3=value3 AND field4=value4;

不会应用任何索引,因为您将直接从最右边调用方法。

您可以在explain 字段possible_keys 上看到它,其值为null

就像最后一个例子:

EXPLAIN SELECT * FROM table WHERE field1=value1 AND field4=value4;

此查询仅对field1 应用索引,而不为field4 应用索引。原因?不使用其他field2field3

您可以在explain 字段possible_keys 上看到它等于my_index 和字段extras 的值Using index, using where

您可以在此处找到有关复合索引的更多信息:

http://www.mysqltutorial.org/mysql-index/mysql-composite-index/

【讨论】:

    【解决方案2】:

    让我们从为每个查询创建最佳索引开始:

    select * from table where field1=value1 and field2=value2;
    INDEX(value1, value2)  -- in either order
    
    select * from table where field3=value3 and field4=value4;
    INDEX(value3, value4)  -- in either order
    
    select * from table where field1=value1 and field2=value2 and field3=value3;
    INDEX(value1, value2, value3)  -- in any order
    
    select * from table where field4=value4;
    INDEX(value4)
    

    现在,让我们看看我们是否可以减少索引的数量:

    INDEX(value1, value2)  -- in either order, and
    INDEX(value1, value2, value3)  -- in any order
    

    可以按如下方式组合得到一个能够很好地处理两个选择的索引:

    INDEX(value1, value2,   -- in either order
          value3)   -- afterwards
    

    同样,

    INDEX(value3, value4)  -- in either order
    INDEX(value4)
    

    -->

    INDEX(value4, value3)  -- in THIS order
    

    因此,对于 那些 SELECTs,两个复合索引是最佳的:

    INDEX(value1, value2,   -- in either order
                          value3)   -- afterwards
    INDEX(value4, value3)  -- in THIS order
    

    但是...您是否提供了所有SELECTs?我怀疑你没有。你真的允许几列的所有组合。这变得非常混乱。我建议您不要进行上述练习,而是找到最可能的组合,构建一些复合索引,然后通过注意 INDEX(a,b,c)INDEX(a,b,d) 的一个很好的替代品来减少它们。

    但是...如果您没有=,情况会变得更糟。构建复合索引时,但首先是 = 列,然后是任何 INs,最后不超过一个“范围”测试。

    但是...如果您使用的是 OR 而不是 AND,那么就别提优化了。

    经验法则:索引不要超过 5 个。

    现在,如果您想重新开始,请使用 real 列名和 real 数据类型,即 real 线索,了解什么是有意义的,我可以进一步帮助你。

    【讨论】: