MySQL索引:它们如何工作?

时间:2011-01-09 03:12:02

标签: mysql indexing

我是MySQL索引的新手。我在MySQL 5.0x上有几个MyISAM表,其中utf8字符集和排序规则各有100k +记录。主键通常是整数。每个表上的许多列可能具有重复值。

我需要快速计算,求和,平均或以其他方式对每张表中的任意数量的字段执行自定义计算,或者加入其他任意数量的字段。

我发现此页面概述了MySQL索引的使用情况:http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html,但我仍然不确定我是否正确使用索引。就在我认为我已经从我想要计算的字段集合中创建完美索引时,我得到“索引必须低于1000字节”错误。

任何人都可以解释如何最有效地创建和使用索引来加速查询吗?

警告:在这种情况下无法升级Mysql。使用Navicat Light进行数据库管理,但不需要此应用程序。

4 个答案:

答案 0 :(得分:8)

当您在MySQL表中的一列或多列上创建索引时,数据库正在创建一个称为B树的数据结构(假设您使用默认索引设置),每个记录的键是串联的索引列中的值。

例如,假设您有一个定义如下的表:

CREATE TABLE mytable (
 id int unsigned auto_increment,
 column_a char(32) not null default '',
 column_b int unsigned not null default 0,
 column_c varchar(512),
 column_d varchar(512),
 PRIMARY KEY (id)
) ENGINE=MyISAM;

然后让我们给它一些数据:

INSERT INTO mytable VALUES (1, 'hello', 2, null, null);
INSERT INTO mytable VALUES (2, 'hello', 3, 'hi', 'there');
INSERT INTO mytable VALUES (3, 'how', 4, 'are', 'you?');
INSERT INTO mytable VALUES (4, 'foo', 5, '', 'bar');

现在假设您决定将关键字添加到column_acolumn_b,如:

ALTER TABLE mytable ADD KEY (column_a, column_b);

数据库将创建上述B树,其中包含四个键,每行一个:

hello-2
hello-3
how-4
foo-5

当您执行引用column_a列的引用或引用column_a AND column_b列的搜索时,数据库将能够使用此索引来缩小记录集的范围必须检查。假设你有一个类似的查询:

SELECT ... FROM mytable WHERE column_a = 'hello';

即使上面的查询没有为column_b列指定值,它仍然可以通过查找以“hello”开头的所有键来利用我们的索引。出于同样的原因,如果您有类似的查询:

SELECT ... FROM mytable WHERE column_b = '2';

此查询将无法使用我们的索引,因为它必须解析索引键本身以尝试确定哪些键的第二个值匹配“2”,这非常低效。

现在,让我们解决您最大长度的原始问题。假设我们尝试创建一个跨越此表中所有四个非PK列的索引:

ALTER TABLE mytable ADD KEY (column_a, column_b, column_c, column_d);

您将收到错误消息:

ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes

在这种情况下,我们的列长度为32,10,512和512,在每个字符的单字节情况下为1066,超过了1000的限制。假设它的DID工作;您将创建以下键:

hello-2-
hello-3-hi-there
how-4-are-you?
foo-5--bar

现在,假设您在column_ccolumn_d中的值非常长,每个值为512个字符。即使在基本的单字节字符集中,您的密钥现在也将超过1000个字节,这正是MySQL所抱怨的。多字节字符集会变得更糟,看似“小”的列仍然可以超出限制。

如果你必须使用一个大的复合键,一个解决方案是使用InnoDB表而不是默认的MyISAM表,它支持更大的密钥长度(3500字节) - 你可以通过交换ENGINE=InnoDB代替在上面的声明中ENGINE=MyISAM。但是,一般来说,如果你使用长按键,你的桌面设计可能有问题。

请记住,单列索引通常比多列索引提供更多实用程序。当您经常/通过在查询中指定所有必要条件时,您希望使用多列索引。此外,正如其他人所提到的,不要索引表的每一列,因为每个索引都会为数据库添加存储开销。您希望将索引限制为查询经常使用的列,如果您需要太多,则应该考虑将表分解为更多逻辑组件。

答案 1 :(得分:1)

索引通常不适合用户能够构建自己的查询的自定义计算。通常,您选择索引以匹配您要运行的特定查询,使用EXPLAIN查看是否正在使用索引。

如果你完全不知道可以执行哪些查询,通常最好每列创建一个索引 - 而一个索引覆盖所有列。

如果您对可能经常运行的查询有所了解,则可以为这些特定查询创建额外的索引。如果您的用户抱怨某些类型的查询运行得太慢,您也可以稍后添加索引。

此外,索引通常对计算计数,总和和平均值没有用,因为这些类型的计算需要查看每一行。

答案 2 :(得分:1)

听起来你正试图在索引中添加太多字段。限制可能是编码所有字段所需的字节数。

索引用于查找记录,因此您要选择“正在”的字段。在这些字段之间进行选择时,您希望选择能够最快地缩小结果的字段。

例如,男性/女性的过滤器通常没有多大帮助,因为您只能节省大约50%的时间。但是,对State进行过滤可能很有用,因为您可以分解为更多类别。但是,如果数据库中几乎每个人都处于单一状态,那么这将无效。

答案 3 :(得分:1)

请记住,索引用于排序和查找行。

您收到的错误消息听起来像是在讨论MyISAM表索引的1000字节前缀限制。来自http://dev.mysql.com/doc/refman/5.0/en/create-index.html

  

此处显示的语句创建了一个   索引使用的前10个字符   名称栏:

     

CREATE INDEX part_of_name ON客户   (名称(10));如果列中的名称   通常在前10个不同   字符,这个索引不应该   比从中创建的索引慢得多   整个名称列。另外,使用   索引的列前缀可以生成   索引文件要小得多,哪个   可以节省大量的磁盘空间   也可能加快INSERT操作。

     

前缀支持和前缀长度   (支持的地方)是存储引擎   依赖。例如,前缀可以   MyISAM最长可达1000字节   表和InnoDB的767字节   表。

也许您可以为有问题的列尝试FULLTEXT索引。