我是MySQL索引的新手。我在MySQL 5.0x上有几个MyISAM表,其中utf8字符集和排序规则各有100k +记录。主键通常是整数。每个表上的许多列可能具有重复值。
我需要快速计算,求和,平均或以其他方式对每张表中的任意数量的字段执行自定义计算,或者加入其他任意数量的字段。
我发现此页面概述了MySQL索引的使用情况:http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html,但我仍然不确定我是否正确使用索引。就在我认为我已经从我想要计算的字段集合中创建完美索引时,我得到“索引必须低于1000字节”错误。
任何人都可以解释如何最有效地创建和使用索引来加速查询吗?
警告:在这种情况下无法升级Mysql。使用Navicat Light进行数据库管理,但不需要此应用程序。
答案 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_a
和column_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_c
和column_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索引。