MySQL中多列索引的字段顺序是否重要

时间:2014-06-19 19:52:35

标签: mysql sql performance indexing

我知道索引的重要性以及联接顺序如何改变性能。我已经完成了一堆与多列索引相关的阅读,但没有找到我的问题的答案。

我很好奇我是否进行多列索引,如果他们指定的顺序很重要。我的猜测是它不会,并且引擎会将它们视为一个组,其中排序无关紧要。但我想验证一下。

例如,来自mysql的网站(http://dev.mysql.com/doc/refman/5.0/en/multiple-column-indexes.html

CREATE TABLE test (
    id         INT NOT NULL,
    last_name  CHAR(30) NOT NULL,
    first_name CHAR(30) NOT NULL,
    PRIMARY KEY (id),
    INDEX name (last_name,first_name)
);

在任何情况下,如果以下情况会更好,或者它是否相同,会不会有任何好处?

CREATE TABLE test (
    id         INT NOT NULL,
    last_name  CHAR(30) NOT NULL,
    first_name CHAR(30) NOT NULL,
    PRIMARY KEY (id),
    INDEX name (first_name,last_name)
);

Specificially:

INDEX name (last_name,first_name)

VS

INDEX name (first_name,last_name)

3 个答案:

答案 0 :(得分:54)

在讨论多列索引时,我使用类比电话簿。电话簿基本上是姓氏的索引,然后是名字。因此排序顺序取决于哪个“列”是第一个。搜索分为几类:

  1. 如果您查找姓氏为Smith的人,您可以轻松找到它们,因为该书按姓氏排序。

  2. 如果你查找姓名为约翰的人,那么电话簿就无济于事,因为约翰斯分散在整本书中。你必须扫描整本电话簿才能找到它们。

  3. 如果您查找具有特定姓氏Smith和特定名字John的人,该书有帮助,因为您发现Smiths排序在一起,并且在该组Smiths中,Johns也按排序顺序找到

  4. 如果您的电话簿按名字排序,则按姓氏排序,对于上述案例#2和#3,书籍的分类将有助于您,但不是案例#1。

    这解释了查找确切值的情况,但如果您按值范围查找会怎么样?假设你想找到所有姓名为John且姓氏以'S'开头的人(Smith,Saunders,Staunton,Sherman等)。约翰斯在每个姓氏中的“J”下排序,但是如果你想要所有姓氏的所有姓氏以“S”开头,则约翰斯不会归为一组。它们再次分散,因此您最终必须扫描姓氏以“S”开头的所有姓名。如果电话簿是按名字和姓氏组织的,那么你会发现所有的约翰在一起,然后在约翰内,所有的'S'姓都将组合在一起。

    因此,多列索引中列的顺序绝对重要。一种类型的查询可能需要索引的特定列顺序。如果您有多种类型的查询,则可能需要多个索引来帮助它们,列的顺序不同。

    您可以阅读我的演示文稿How to Design Indexes, Really以获取更多信息。

答案 1 :(得分:8)

两个指数不同。这在MySQL和其他数据库中都是如此。 MySQL在解释documentation中的不同内容方面做得非常好。

考虑两个指标:

create index idx_lf on name(last_name, first_name);
create index idx_fl on name(first_name, last_name);

这两项都应该同样有效:

where last_name = XXX and first_name = YYY

idx_lf对于以下条件是最佳的:

where last_name = XXX
where last_name like 'X%'
where last_name = XXX and first_name like 'Y%'
where last_name = XXX order by first_name

idx_fl将是以下内容的最佳选择:

where first_name = YYY
where first_name like 'Y%'
where first_name = YYY and last_name like 'X%'
where first_name = XXX order by last_name

对于其中许多情况,两个索引都可以使用,但其中一个是最佳的。例如,考虑带有查询的idx_lf:

where first_name = XXX order by last_name

MySQL可以使用idx_lf读取整个表,然后在order by之后进行过滤。我不认为这是实践中的优化选项(对于MySQL),但这可能发生在其他数据库中。

答案 2 :(得分:5)

一般规则是,你想要把最具选择性的 - 也就是那个能给你最少的结果 - 首先。因此,如果您要在表格上创建多列索引,其中包含10个可能值的status列,以及dateAdded列,您通常会编写类似

的查询
SELECT * FROM myTable WHERE status='active' and dateAdded='2010-10-01'

...然后你首先需要dateAdded,因为这会将扫描限制为几行,而不是行的10%(或任何比例为“活动”)。

这需要相当多的思考和调整;你应该看看Lahdenmaki和Leach的书。