Làm cách nào để thêm chỉ mục vào bảng MySQL?


407

Tôi đã có một bảng MySQL rất lớn với khoảng 150.000 hàng dữ liệu. Hiện tại, khi tôi cố gắng chạy

SELECT * FROM table WHERE id = '1';

mã chạy tốt vì trường ID là chỉ mục chính. Tuy nhiên, để phát triển gần đây trong dự án, tôi phải tìm kiếm cơ sở dữ liệu theo một lĩnh vực khác. Ví dụ:

SELECT * FROM table WHERE product_id = '1';

Lĩnh vực này trước đây không được lập chỉ mục; tuy nhiên, tôi đã thêm một cái, vì vậy mysql bây giờ lập chỉ mục trường, nhưng khi tôi cố chạy truy vấn trên, nó chạy rất chậm. Một truy vấn EXPLAIN cho thấy rằng không có chỉ mục nào cho trường Product_id khi tôi đã thêm một truy vấn và kết quả là truy vấn mất bất kỳ nơi nào từ 20 phút đến 30 phút để trả về một hàng.

Kết quả GIẢI THÍCH đầy đủ của tôi là:

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

Có thể hữu ích khi lưu ý rằng tôi vừa xem và trường ID được lưu dưới dạng INT trong khi trường PRODUCT_ID được lưu dưới dạng VARCHAR. Đây có thể là nguồn gốc của vấn đề?


1
Bạn có thể gửi EXPLAINkết quả đầy đủ ? Bạn có chắc chắn rằng nó không có chỉ số? Hoặc là chỉ mục ở đó, nhưng MySQL chọn không sử dụng nó?
VoteyDiscipl

169
Một bảng lớn sẽ có 150.000.000 hồ sơ. Một bảng rất lớn có 15.000.000.000 hồ sơ. Một bảng có kích thước trung bình có 150.000. Để tham khảo trong tương lai.
usumoio

4
Xin lưu ý rằng 'HOẶC' có thể khiến MySql không sử dụng các chỉ mục. Tôi đã có một truy vấn với 3 OR. Mỗi người gia công một chỉ mục và chạy trong 15ms, Tất cả cùng nhau mất từ ​​25 giây đến hết thời gian. Vì vậy, tôi đã thực hiện 3 truy vấn và UNION đã kết hợp chúng với nhau, cũng mất 15ms trên 500.000 hàng.
Leif Neland

Hãy xem xét loại dữ liệu bạn đang lưu trữ. Hiệu suất có thể thay đổi dựa trên loại dữ liệu bạn đang so sánh. Như bạn đã nói PRODUCT_ID là loại dữ liệu VARCHAR, hãy thử thay đổi nó thành INT và lập chỉ mục cột.
gilbertdim

Câu trả lời:


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

Không bao giờ so sánh integervới stringstrong MySQL. Nếu idint, loại bỏ các trích dẫn.


Tôi đã thêm chỉ mục bằng SQL chính xác đó nhưng có vẻ như nó chưa được "áp dụng" cho dữ liệu và truy vấn EXPLAIN cho thấy không có chỉ mục nào cho trường.
Michael

1
Quan tâm để kiểm tra chỉ mục với BẢNG TẠO SHOW, hoặc bạn đã làm điều đó chưa?
Wrikken

33
Sử dụng SHOW INDEXES FROM YOURTABLE dev.mysql.com/doc/refman/5.0/en/show-index.html để kiểm tra xem các chỉ mục đã được thêm chưa
Timo Huovinen

6
Hôm nay tôi đã có một vấn đề chính xác mà @Michael mô tả và giải pháp là "Không bao giờ so sánh số nguyên với các chuỗi trong mysql." Cảm ơn bạn.
user12345

@Wrikken Tôi đã thêm chỉ mục của mình và sử dụng lệnh của bạn HIỂN THỊ INDEXES TỪ BẠN. Nó hiện lên nhưng tôi không nghĩ nó được sử dụng trong khi tôi truy vấn bảng của mình. Tôi có phải thay đổi truy vấn chọn khi sử dụng chỉ mục không?
Ced

148
ALTER TABLE TABLE_NAME ADD INDEX (COLUMN_NAME);

97
Trong MySQL, nếu bạn sử dụng ALTER TABLE tbl ADD INDEX (col)thay vì ALTER TABLE tbl ADD INDEX col (col), sau đó sử dụng ALTER TABLE tbl ADD INDEX (col)nhiều hơn một lần sẽ tiếp tục bổ sung các chỉ số được đặt tên col_2, col_3... mỗi lần. Trong khi sử dụng ALTER TABLE tbl ADD INDEX col (col)lần thứ 2, sẽ cho ERROR 1061 (42000): Duplicate key name 'col'.
Abhishek Oza

82

Bạn có thể sử dụng cú pháp này để thêm một chỉ mục và kiểm soát loại chỉ mục (HASH hoặc 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;

Bạn có thể tìm hiểu về sự khác biệt giữa các chỉ mục BTREE và HASH tại đây: http://dev.mysql.com/doc/refman/5.5/en/index-btree-hash.html


1
Hash chuyển đổi thành btree khi tôi thấy bằng cách sử dụng các chỉ mục hiển thị.
RN Kushwaha

1
Điều gì sẽ là mặc định từ Hash và BTree, nếu tôi không chỉ định bất kỳ?
Bhavuk Mathur

2
@RNKushwaha vì InnoDB và MyIsam không hỗ trợ HASH, AFAIK, chỉ có các công cụ lưu trữ Bộ nhớ và NDB hỗ trợ nó
Hiếu Võ

60

Điều đáng chú ý là nhiều chỉ mục trường có thể cải thiện đáng kể hiệu năng truy vấn của bạn. Vì vậy, trong ví dụ trên, chúng tôi giả sử ProductID là trường duy nhất để tra cứu nhưng là truy vấn để nói ProductID = 1 AND Category = 7 thì chỉ mục nhiều cột sẽ giúp. Điều này đạt được với những điều sau đây:

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

Ngoài ra, chỉ mục phải phù hợp với thứ tự của các trường truy vấn. Trong ví dụ mở rộng của tôi, chỉ mục phải là (ProductID, Category) chứ không phải theo cách khác.


1
Đẹp, đặt tên rõ ràng cho chỉ mục cho phép đảo ngược dễ dàng.
Sam Berry

Bạn có thể trích dẫn nguồn của the index should match the order of the query fields?
Bishwas Mishra

58

Chỉ mục của hai loại có thể được thêm vào: khi bạn xác định khóa chính, MySQL sẽ lấy nó làm chỉ mục theo mặc định.

Giải trình

Khóa chính là chỉ mục

Xem xét bạn có một tbl_studentbảng và bạn muốn student_idlàm khóa chính:

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

Câu lệnh trên thêm một khóa chính, có nghĩa là các giá trị được lập chỉ mục phải là duy nhất và không thể là NULL.

Chỉ định tên chỉ mục

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

Tuyên bố trên sẽ tạo ra một chỉ mục bình thường với student_indextên.

Tạo chỉ mục duy nhất

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

Ở đây, student_unique_indexlà tên chỉ mục được gán cho student_id và tạo một chỉ mục cho các giá trị phải là duy nhất (ở đây null có thể được chấp nhận).

Tùy chọn toàn văn

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

Câu lệnh trên sẽ tạo tên chỉ mục Fulltext với student_fulltext_index, mà bạn cần MyISAM Mysql Engine.

Làm thế nào để loại bỏ chỉ mục?

DROP INDEX `student_index` ON `tbl_student`

Làm thế nào để kiểm tra các chỉ số có sẵn?

SHOW INDEX FROM `tbl_student`

17

Bạn nói rằng bạn có một chỉ số, giải thích nói khác. Tuy nhiên, nếu bạn thực sự làm, đây là cách tiếp tục:

Nếu bạn có một chỉ mục trên cột và MySQL quyết định không sử dụng nó, thì có thể bởi vì:

  1. Có một chỉ mục khác trong truy vấn mà MySQL thấy phù hợp hơn để sử dụng và nó chỉ có thể sử dụng một chỉ mục. Giải pháp thường là một chỉ mục bao trùm nhiều cột nếu phương thức truy xuất thông thường của chúng là theo giá trị nhiều hơn một cột.
  2. MySQL quyết định có nhiều hàng phù hợp và nghĩ rằng một bảng có thể nhanh hơn. Nếu đó không phải là trường hợp, đôi khi mộtANALYZE TABLE giúp đỡ.
  3. Trong các truy vấn phức tạp hơn, nó quyết định không sử dụng nó dựa trên voodoo suy nghĩ cực kỳ thông minh trong kế hoạch truy vấn mà vì một lý do nào đó không phù hợp với yêu cầu hiện tại của bạn.

Trong trường hợp (2) hoặc (3), bạn có thể dỗ MySQL sử dụng chỉ mục bằng sytax gợi ý chỉ mục , nhưng nếu có, hãy chắc chắn chạy một số thử nghiệm để xác định xem nó có thực sự cải thiện hiệu suất để sử dụng chỉ mục hay không khi bạn gợi ý .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.