我最近一直在考虑我的数据库索引,过去我只是非常挑衅地将它们作为事后的想法投入其中,并且如果它们是正确的甚至是帮助的话,从未真正考虑过。我读过相互矛盾的信息,有人说更多的索引更好,有些则索引太多,所以我希望得到一些澄清,并在这里学到一点。
假设我有这个假设的表格:
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
用于对结果集进行排序。
现在,如果我添加搜索参数:
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_name
,widget_part_number
和widget_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_index
和widgets.widget_id
主键索引进行连接,但排序呢?它会同时使用widget_name_index
和special_title_index
吗?
我不想长时间徘徊,我可以想到无数的场景。显然,对于真实场景而言,这可能会变得更加复杂,而不是几个简单的表格。任何澄清将不胜感激。
答案 0 :(得分:5)
通过最佳实践,您不必在定义表示意图时创建索引。在应用程序中创建查询时,最好创建索引。在大多数情况下,您将从单列索引开始以满足查询。如果要在查询中使用多个列,可以创建覆盖索引。
覆盖索引是包含两列或更多列的索引。如果索引满足查询的所有列要求,则存储引擎可以从索引获取所有结果,而不是在磁盘I / O操作中踢。因此,在创建使用更多列的查询时,您可以创建覆盖所有必需列的新索引,也可以扩展现有索引以包含更多列。
在执行上述任何一项操作时,您必须考虑一些因素。只有当索引的最左列可以在查询中使用时,MySQL才会考虑索引。否则,它只是寻找整个表来获取结果。因此,如果您可以扩展现有索引而不影响使用该索引的所有查询,那么这将是明智的选择。否则,您可以继续为新查询创建新索引。有时,可以调整查询以适应索引结构。
答案 1 :(得分:3)
索引加速选择,但减慢插入和更新速度。您无需为可以想象的每个可能的列组合创建索引。我通常只是创建明显的索引,我知道我将经常使用,只有在我进行性能测量后才能看到需要它们时才添加更多。即使数据库未覆盖查询中的所有列,数据库仍然可以使用索引。
答案 2 :(得分:3)
查询中只使用了一个索引。幸运的是,您可以创建一个涵盖多个列的索引:
ALTER TABLE widgets ADD INDEX name_and_price_index(widget_name, widget_price);
如果您按widget_name 或 widget_name + widget_price(但不仅仅是widget_price)进行SELECT,则将使用上述索引。
正如MitMaro所指出的那样,在查询中使用EXPLAIN来查看MySQL必须选择的索引,以及它最终使用的索引。有关更多详细信息,请参阅here。