2009-11-21 40 views
6

最近我一直在想我的数据库索引,过去我只是一种非夸张地把它们抛入其中,并且从未真正考虑过它们是否正确或甚至帮助。我读过冲突的信息,有人说更多的索引更好,其他人索引太多都不好,所以我希望能够澄清一些,并在这里学习一下。需要对MySQL索引进行一点说明

比方说,我有这样的假设表:

CREATE TABLE widgets (
    widget_id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, 
    widget_name VARCHAR(50) NOT NULL, 
    widget_part_number VARCHAR(20) NOT NULL, 
    widget_price FLOAT NOT NULL, 
    widget_description TEXT NOT NULL 
); 

我通常会添加索引将被加入,将上最常被排序字段和字段:

ALTER TABLE widgets ADD INDEX widget_name_index(widget_name); 

所以现在,在查询中,例如:

SELECT w.* FROM widgets AS w ORDER BY w.widget_name ASC 

widget_name_index用于SOR结果集。

现在,如果我添加一个搜索参数:

SELECT w.* FROM widgets AS w 
WHERE w.widget_price > 100.00 
ORDER BY w.widget_name ASC 

我想我需要一个新的索引。

ALTER TABLE widgets ADD INDEX widget_price_index(widget_price); 

但是,它会使用两个索引吗?据我所知也不会......

ALTER TABLE widgets ADD INDEX widget_price_name_index(widget_price, widget_name); 

现在widget_price_name_index将用于两个选择和订购的记录。但是,如果我想扭转局面,并做什么:

SELECT w.* FROM widgets AS w 
WHERE w.widget_name LIKE '%foobar%' 
ORDER BY w.widget_price ASC 

widget_price_name_index用于此?或者我还需要widget_name_price_index

ALTER TABLE widgets ADD INDEX widget_name_price_index(widget_name, widget_price); 

现在,如果我有搜索widget_namewidget_part_numberwidget_description一个搜索框?

ALTER TABLE widgets 
ADD INDEX widget_search(widget_name, widget_part_number, widget_description); 

如果最终用户可以按任何列进行排序,该怎么办?很容易看到,如果我只有5列的话,我可能会得到十多个索引。

如果再加上另一个表:

CREATE TABLE specials (
    special_id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, 
    widget_id INT UNSIGNED NOT NULL, 
    special_title VARCHAR(100) NOT NULL, 
    special_discount FLOAT NOT NULL, 
    special_date DATE NOT NULL 
); 
ALTER TABLE specials ADD INDEX specials_widget_id_index(widget_id); 
ALTER TABLE specials ADD INDEX special_title_index(special_title); 

SELECT w.widget_name, s.special_title 
FROM widgets AS w 
INNER JOIN specials AS s ON w.widget_id=s.widget_id 
ORDER BY w.widget_name ASC, s.special_title ASC 

我假定这将使用大约排序widget_id_indexwidgets.widget_id主键索引的加盟,但什么?它会同时使用widget_name_indexspecial_title_index

我不想漫步太久,有无数场景可以让我想起来。显然,这可能会变得更加复杂与真实世界的场景,而不是几个简单的表。任何澄清将不胜感激。

+4

我不会把这作为答案,因为我不是专业的数据库,但在MySQL中,您可以在查询之前使用EXPLAIN来提供有关使用哪些索引的一些信息。 http://dev.mysql.com/doc/refman/5.0/en/explain.html – MitMaro 2009-11-21 04:05:47

回答

5

通过最佳实践,您无需在定义表格原理图时创建索引。在您的应用程序中创建查询时创建索引总是更好。在大多数情况下,您将以单列索引开始以满足查询。如果您想在查询中使用多个列,则可以创建一个覆盖索引。

覆盖索引是其中有两列或更多列的索引。如果索引满足查询的所有列要求,则存储引擎可以从索引获取所有结果,而不是在磁盘I/O操作中踢脚。因此,在创建使用更多列的查询时,您可以创建覆盖所有必需列的新索引,或者,可以扩展现有索引以包含更多列。

在做上述任何一项时,您必须考虑一些问题。只有在查询中可以使用索引的最左列时,MySQL才会考虑索引。否则,它只是寻找整个表来获取结果。因此,如果您可以扩展现有索引而不影响所有使用该索引的查询,那么这将是一个明智的选择。否则,您可以继续为新查询创建一个新索引。有时,可以调整查询以适应索引结构。

+0

'而不是踢在磁盘I/O操作'您认为索引数据存储在哪里? – 2013-10-23 09:36:40

3

索引加速选择,但减慢插入和更新。您无需为您想象的每个可能的列组合创建索引。我通常只是创建我知道我会经常使用的明显索引,并且只有在进行性能测量后才能看到它们需要时才添加更多索引。即使数据库没有涵盖查询中的所有列,数据库仍然可以使用索引。

+0

更多的索引可能会更好。索引太多肯定更糟。 – 2009-11-21 04:31:45

3

查询中只使用了一个索引。幸运的是,你可以创建覆盖多个列的索引:

ALTER TABLE widgets ADD INDEX name_and_price_index(widget_name, widget_price); 

,如果你WIDGET_NAME选择由上述指标将被用于 WIDGET_NAME + widget_price(但不只是widget_price)。

正如MitMaro指出的那样,在查询中使用EXPLAIN来查看MySQL可以选择的索引以及它最终使用的索引。有关更多详细信息,请参见here

+0

最近版本的MySQL有索引合并,在某些情况下可以使用多个索引。 – peufeu 2009-11-21 20:52:10