MySQLテーブルにインデックスを追加するにはどうすればよいですか?


407

約150,000行のデータを含む非常に大きなMySQLテーブルがあります。現在、実行してみると

SELECT * FROM table WHERE id = '1';

IDフィールドがプライマリインデックスであるため、コードは正常に実行されます。しかし、プロジェクトの最近の進展のために、別のフィールドでデータベースを検索する必要があります。例えば:

SELECT * FROM table WHERE product_id = '1';

このフィールドは以前に索引付けされていませんでした。ただし、1つ追加したので、mysqlはフィールドにインデックスを付けますが、上記のクエリを実行しようとすると、実行速度が非常に遅くなります。EXPLAINクエリにより、product_idフィールドに既にインデックスを追加している場合、インデックスがないことがわかります。その結果、クエリは20分から30分で1つの行を返します。

私の完全な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はそれを使用しないことを選択していますか?
VotyDisciple

169
大きなテーブルには150,000,000のレコードがあります。非常に大きなテーブルには、15,000,000,000レコードがあります。平均サイズのテーブルは150,000です。今後の参考のために。
usumoio 2012年

4
'OR'はMySqlがインデックスを使用しないようにすることができることに注意してください。3つのORでクエリがありました。それぞれがインデックスを作成し、15ミリ秒で実行されました。すべて一緒に25秒からタイムアウトまでかかりました。したがって、3つのクエリを作成し、それらをまとめてUNIONしました。また、500.000行で15ミリ秒かかりました。
Leif

保存するデータ型を検討してください。パフォーマンスは、比較しているデータ型に基づいて変化する可能性があります。PRODUCT_IDはVARCHARデータ型だと言ったので、それをINTに変更して、列にインデックスを付けてみてください。
gilbertdim

回答:


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

MySQL と比較integerしないでくださいstrings。場合idint、引用符を削除します。


その正確なSQLを使用して既にインデックスを追加しましたが、データに「適用」されていないようで、EXPLAINクエリはフィールドにインデックスがないことを示しています。
マイケル

1
SHOW CREATE TABLEを使用してインデックスを確認するか、すでに確認しましたか?
Wrikken、

33
SHOW INDEXES FROM YOURTABLE dev.mysql.com/doc/refman/5.0/en/show-index.htmlを使用して、インデックスが追加されているかどうかを確認します
Timo Huovinen

6
今日、@ Michaelが説明する正確な問題があり、解決策は「整数をMySQLの文字列と決して比較しない」ことでした。ありがとうございました。
user12345 2014

@Wrikken私は自分のインデックスを追加し、コマンドSHOW INDEXES FROM YOURTABLEを使用しました。表示されますが、テーブルのクエリ中に使用されているとは思いません。インデックスを使用するときに選択クエリを変更する必要がありますか?
Ced

148
ALTER TABLE TABLE_NAME ADD INDEX (COLUMN_NAME);

97
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)2回目を使用するのに対し、を与え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
showインデックスの使用を確認すると、ハッシュがbtreeに変換されます。
RNクシュワハ2015年

1
何も指定しないと、HashとBTreeのデフォルトはどうなりますか?
Bhavuk Mathur

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
インデックスに明示的に名前を付けると、簡単に逆転できます。
Sam Berry

の出典を引用できますthe index should match the order of the query fieldsか?
Bishwas Mishra

58

2つのタイプのインデックスを追加できます。主キーを定義すると、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_indexMyISAM Mysql Engineが必要なフルテキストインデックス名をで作成します。

インデックスを削除するには?

DROP INDEX `student_index` ON `tbl_student`

利用可能なインデックスを確認する方法は?

SHOW INDEX FROM `tbl_student`

17

あなたはあなたがインデックスを持っていると言い、説明はそうではないと言っています。ただし、本当にそうする場合、これは続行する方法です。

列にインデックスがあり、MySQLがそれを使用しないと決定した場合、次の理由が考えられます。

  1. MySQLの使用にはより適切であるとMySQLが判断したクエリに別のインデックスがあり、使用できるのは1つだけです。通常の検索方法が複数の列の値による場合、解決策は通常、複数の列にまたがるインデックスです。
  2. MySQLは一致する行が多数あると判断し、テーブルスキャンの方が高速だと考えています。それが当てはまらない場合は、ANALYZE TABLE役立つことがあります。
  3. より複雑なクエリでは、なんらかの理由で現在の要件に適合しないクエリプランの非常にインテリジェントな考え抜かれたブードゥーに基づいてそれを使用しないことを決定します。

(2)または(3)の場合、MySQLをインデックスヒント構文インデックスを使用するように調整できますが、使用する場合は、いくつかのテストを実行して、ヒントを使用することでインデックスを実際に使用してパフォーマンスが向上するかどうかを確認してください。 。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.