我知道索引的重要性以及联接顺序如何改变性能。我已经完成了一堆与多列索引相关的阅读,但没有找到我的问题的答案。
我很好奇我是否进行多列索引,如果他们指定的顺序很重要。我的猜测是它不会,并且引擎会将它们视为一个组,其中排序无关紧要。但我想验证一下。
例如,来自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)
答案 0 :(得分:54)
在讨论多列索引时,我使用类比电话簿。电话簿基本上是姓氏的索引,然后是名字。因此排序顺序取决于哪个“列”是第一个。搜索分为几类:
如果您查找姓氏为Smith的人,您可以轻松找到它们,因为该书按姓氏排序。
如果你查找姓名为约翰的人,那么电话簿就无济于事,因为约翰斯分散在整本书中。你必须扫描整本电话簿才能找到它们。
如果您查找具有特定姓氏Smith和特定名字John的人,该书有帮助,因为您发现Smiths排序在一起,并且在该组Smiths中,Johns也按排序顺序找到
如果您的电话簿按名字排序,则按姓氏排序,对于上述案例#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的书。