如何为MySQL表添加索引?


407

我有一个非常大的MySQL表,其中包含约15万行数据。目前,当我尝试运行

SELECT * FROM table WHERE id = '1';

该代码运行良好,因为ID字段是主要索引。但是,对于该项目的最新开发,我必须按另一个字段搜索数据库。例如:

SELECT * FROM table WHERE product_id = '1';

该字段先前未编制索引;但是,我添加了一个,因此mysql现在为该字段建立索引,但是当我尝试运行上述查询时,它运行非常缓慢。一个EXPLAIN查询显示,当我已经添加了product_id字段时,没有针对product_id字段的索引,因此该查询需要20分钟到30分钟的任何时间才能返回单行。

我完整的EXPLAIN结果是:

| id | select_type | table | type | possible_keys| key  | key_len | ref  | rows  | Extra       |
+----+-------------+-------+------+--------------+------+---------+------+-------+------------------+
|  1 | SIMPLE      | table | ALL  | NULL         | NULL | NULL    | NULL |157211 | Using where |
+----+-------------+-------+------+--------------+------+---------+------+-------+------------------+

注意,我刚刚看了一下,ID字段存储为INT,而PRODUCT_ID字段存储为VARCHAR,这可能会有所帮助。这可能是问题的根源吗?


1
您可以发布完整EXPLAIN结果吗?您确定没有索引吗?还是索引在那里,但是MySQL选择不使用它?
VoteyDisciple 2010年

169
一个大表将具有150,000,000条记录。一个非常大的表具有15,000,000,000条记录。一张平均大小的表有150,000。备查。
usumoio 2012年

4
请注意,“ OR”可以使MySql不使用索引。我有3个OR的查询。每个进程执行一次索引,耗时15毫秒,总计耗时25秒至超时。因此,我进行了3个查询,并一起进行了UNION处理,在500.000行上也花费了15ms。
雷夫·尼兰

考虑要存储的数据类型。性能可能会根据您正在比较的数据类型而变化。如您所说PRODUCT_ID是VARCHAR数据类型,请尝试将其更改为INT并为该列建立索引。
gilbertdim

Answers:


606
ALTER TABLE `table` ADD INDEX `product_id_index` (`product_id`)

永远不要比较integer,以strings在MySQL。如果idint,请删除引号。


我已经使用确切的SQL添加了索引,但似乎还没有“将其应用于数据”,并且EXPLAIN查询显示该字段没有索引。
迈克尔

1
希望使用SHOW CREATE TABLE检查索引,还是已经完成了?
2010年

33
使用SHOW INDEXES FROM YOURTABLE dev.mysql.com/doc/refman/5.0/en/show-index.html检查是否已添加索引
Timo Huovinen 2013年

6
今天,我遇到了@Michael描述的确切问题,解决方案是“从不将整数与mysql中的字符串进行比较”。谢谢。
user12345

@Wrikken我添加了索引并使用了您的命令SHOW INDEXES FROM YOURTABLE。它显示了,但我认为查询表时不使用它。使用索引时是否需要更改选择查询?
2013年

147
ALTER TABLE TABLE_NAME ADD INDEX (COLUMN_NAME);

96
在MySQL中,如果你使用ALTER TABLE tbl ADD INDEX (col)的不是ALTER TABLE tbl ADD INDEX col (col),然后使用ALTER TABLE tbl ADD INDEX (col)不止一次将继续添加名为指标col_2col_3......每一次。而使用ALTER TABLE tbl ADD INDEX col (col)第二次,将给出ERROR 1061 (42000): Duplicate key name 'col'
Abhishek Oza 2014年

82

您可以使用此语法添加索引并控制索引的类型(HASH或BTREE)。

create index your_index_name on your_table_name(your_column_name) using HASH;
or
create index your_index_name on your_table_name(your_column_name) using BTREE;

您可以在此处了解BTREE和HASH索引之间的区别:http : //dev.mysql.com/doc/refman/5.5/en/index-btree-hash.html


1
当我看到使用显示索引时,哈希转换为btree。
RN库什瓦哈2015年

1
如果我未指定,则Hash和BTree的默认值是什么?
Bhavuk Mathur's

2
@RNKushwaha,因为InnoDB和MyIsam不支持HASH,AFAIK,仅内存和NDB存储引擎支持它
Hieu Vo

60

值得注意的是,多个字段索引可以大大提高查询性能。因此,在上面的示例中,我们假定ProductID是要查找的唯一字段,但是如果查询中说ProductID = 1 AND Category = 7,则使用多列索引很有帮助。这可以通过以下方式实现:

ALTER TABLE `table` ADD INDEX `index_name` (`col1`,`col2`)

此外,索引应与查询字段的顺序匹配。在我的扩展示例中,索引应该是(ProductID,Category),而不是相反。


1
很好,显式命名索引可以轻松逆转。
山姆·贝瑞

你能引用来源the index should match the order of the query fields吗?
比什瓦斯·米什拉

58

可以添加两种类型的索引:定义主键时,MySQL默认将其作为索引。

说明

主键作为索引

考虑您有一个tbl_student表,并且想要student_id作为主键:

ALTER TABLE `tbl_student` ADD PRIMARY KEY (`student_id`)

上面的语句添加了一个主键,这意味着索引值必须唯一且不能为NULL。

指定索引名称

ALTER TABLE `tbl_student` ADD INDEX student_index (`student_id`)

上面的语句将创建一个具有student_index名称的普通索引。

创建唯一索引

ALTER TABLE `tbl_student` ADD UNIQUE student_unique_index (`student_id`)

此处,student_unique_index是分配给student_id的索引名称,并创建一个索引,其值必须唯一(此处可以接受null)。

全文选项

ALTER TABLE `tbl_student` ADD FULLTEXT student_fulltext_index (`student_id`)

上面的语句将创建具有以下内容的全文索引名称: student_fulltext_index,为此您需要MyISAM Mysql Engine。

如何删除索引?

DROP INDEX `student_index` ON `tbl_student`

如何检查可用索引?

SHOW INDEX FROM `tbl_student`

17

您说您有一个索引,否则说明说不。但是,如果确实如此,这是继续的方法:

如果您在该列上有一个索引,而MySQL决定不使用它,则可能是因为:

  1. MySQL认为在查询中还有另一个索引更适合使用,它只能使用一个。如果通常的检索方法是按多于一列的值进行检索,则解决方案通常是跨越多列的索引。
  2. MySQL决定有很多匹配的行,并认为tablescan可能更快。如果不是这种情况,有时会有所ANALYZE TABLE帮助。
  3. 在更复杂的查询中,它会基于查询原因中的某种非常聪明的深思熟虑的伏都教决定不使用它,由于某种原因,该伏都教不符合您当前的要求。

在(2)或(3)的情况下,您可以通过索引提示sytax诱使 MySQL使用索引,但是如果这样做,请确保运行一些测试以确定它是否确实提高了按提示使用索引的性能。 。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.