【问题标题】:Need a little clarification on MySQL Indexes需要一点关于 MySQL 索引的说明
【发布时间】:2010-12-18 23:15:59
【问题描述】:

我最近一直在考虑我的数据库索引,过去我只是在事后才毫不客气地把它们扔进去,从来没有真正考虑过它们是否正确甚至有帮助。我读过相互矛盾的信息,有人说索引越多越好,而其他人说索引太多不好,所以我希望在这里得到一些澄清和了解。

假设我有这个假设的表格:

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_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 吗?

我不想啰嗦太久,我可以想出无数种场景。显然,对于现实世界的场景,而不是几个简单的表格,这可能会变得更加复杂。任何澄清将不胜感激。

【问题讨论】:

  • 我不会将此作为答案,因为我不是数据库方面的专家,但在 mysql 中,您可以在查询之前使用 EXPLAIN 来提供有关使用哪些索引的一些信息。 dev.mysql.com/doc/refman/5.0/en/explain.html

标签: mysql database-design indexing database


【解决方案1】:

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

【讨论】:

  • 更多索引可能会更好。索引过多肯定会更糟。
【解决方案2】:

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

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

【讨论】:

  • 最近的 MySQL 版本有索引合并,在某些情况下可以使用多个索引。
【解决方案3】:

根据最佳实践,您不必在定义表格示意图时创建索引。在应用程序中创建查询时创建索引总是更好。在大多数情况下,您将从单列索引开始以满足查询。如果你想在一个查询中使用很多列,你可以创建一个覆盖索引。

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

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

【讨论】:

  • instead of kicking in a disk I/O operation你认为索引数据存储在哪里?
猜你喜欢
  • 1970-01-01
  • 2021-09-28
  • 2019-05-14
  • 1970-01-01
  • 2016-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-27
相关资源
最近更新 更多