Làm thế nào để các chỉ mục MySQL hoạt động?


402

Tôi thực sự quan tâm đến cách các chỉ mục MySQL hoạt động, cụ thể hơn, làm thế nào họ có thể trả lại dữ liệu được yêu cầu mà không quét toàn bộ bảng?

Nó lạc đề, tôi biết, nhưng nếu có ai đó có thể giải thích điều này cho tôi một cách chi tiết, tôi sẽ rất, rất biết ơn.



Đây là một câu hỏi rất rộng. Nếu bạn có một ví dụ cụ thể về truy vấn sẽ không sử dụng chỉ mục và bạn không biết tại sao, bạn có thể đăng nó và mọi người có thể giúp đỡ.
Hammerite

SELECT * FROM members WHERE id = '1'- vậy tại sao với chỉ số nó hoạt động nhanh hơn? Chỉ số đó làm gì ở đây?
good_evening

2
Trông giống như một truy vấn chỉ tìm kiếm một bản ghi được lập chỉ mục cụ thể (có thể được xác định bởi khóa chính). Chỉ mục làm cho điều này nhanh hơn vì nó được lưu trữ trong bộ nhớ, hàng chỉ mục tương ứng có thể được xem xét và nó chứa một con trỏ tới nơi lưu trữ dữ liệu thực tế. Vì vậy, MySQL có thể đi đến vị trí chính xác trong bảng mà không cần phải quét bảng.
Hammerite

Câu trả lời:


513

Về cơ bản, một chỉ mục trên bảng hoạt động giống như một chỉ mục trong một cuốn sách (đó là nơi tên đến từ đó):

Giả sử bạn có một cuốn sách về cơ sở dữ liệu và bạn muốn tìm một số thông tin về lưu trữ. Nếu không có chỉ mục (giả sử không có viện trợ nào khác, chẳng hạn như mục lục), bạn sẽ phải lần lượt đi qua từng trang, cho đến khi bạn tìm thấy chủ đề (đó là a full table scan). Mặt khác, một chỉ mục có một danh sách các từ khóa, vì vậy bạn tham khảo chỉ mục và xem nó storageđược đề cập ở các trang 113-120,231 và 354. Sau đó, bạn có thể lật trực tiếp các trang đó mà không cần tìm kiếm (đó là tìm kiếm với chỉ số, có phần nhanh hơn).

Tất nhiên, chỉ số này sẽ hữu ích như thế nào, phụ thuộc vào nhiều thứ - một vài ví dụ, sử dụng simile ở trên:

  • nếu bạn có một cuốn sách về cơ sở dữ liệu và lập chỉ mục từ "cơ sở dữ liệu", bạn sẽ thấy nó được đề cập ở các trang 1-59,61-290 và 292 đến 400. Trong trường hợp đó, chỉ mục đó không giúp ích nhiều và nó có thể nhanh hơn để đi qua từng trang một (trong cơ sở dữ liệu, đây là "tính chọn lọc kém").
  • Đối với một cuốn sách 10 trang, sẽ không có ý nghĩa gì khi tạo một chỉ mục, vì bạn có thể kết thúc với một cuốn sách 10 trang có tiền tố là một chỉ mục 5 trang, điều này thật ngớ ngẩn - chỉ cần quét 10 trang và thực hiện với nó .
  • Chỉ mục cũng cần phải hữu ích - thường không có điểm nào để lập chỉ mục, ví dụ tần suất của chữ "L" trên mỗi trang.

3
Bạn đang giải thích nó là gì chứ không phải nó hoạt động như thế nào trong nội bộ.
Tutu Kumari

@Tutu Kumari: Xem bản sửa đổi của câu hỏi; cũng vui lòng sửa lại câu trả lời để phù hợp với câu hỏi hiện tại (lưu ý các loại công cụ và chỉ mục khác nhau - xem ví dụ: tài liệu ở đây: dev.mysql.com/doc/refman/8.0/en/index-btree-hash.html )
Piskvor rời khỏi tòa nhà

259

Điều đầu tiên bạn phải biết là các chỉ mục là một cách để tránh quét toàn bộ bảng để có được kết quả mà bạn đang tìm kiếm.

Có nhiều loại chỉ mục khác nhau và chúng được triển khai trong lớp lưu trữ, vì vậy không có tiêu chuẩn nào giữa chúng và chúng cũng phụ thuộc vào công cụ lưu trữ mà bạn đang sử dụng.

InnoDB và chỉ số B + Tree

Đối với InnoDB, loại chỉ mục phổ biến nhất là chỉ mục dựa trên B + Tree, lưu trữ các phần tử theo thứ tự được sắp xếp. Ngoài ra, bạn không phải truy cập vào bảng thực để lấy các giá trị được lập chỉ mục, điều này làm cho cách truy vấn của bạn trở lại nhanh hơn.

"Vấn đề" về loại chỉ mục này là bạn phải truy vấn giá trị ngoài cùng bên trái để sử dụng chỉ mục. Vì vậy, nếu chỉ mục của bạn có hai cột, giả sử last_name và first_name, thứ tự bạn truy vấn các trường này rất quan trọng .

Vì vậy, đưa ra bảng sau:

CREATE TABLE person (
    last_name VARCHAR(50) NOT NULL,
    first_name VARCHAR(50) NOT NULL,
    INDEX (last_name, first_name)
);

Truy vấn này sẽ tận dụng lợi thế của chỉ mục:

SELECT last_name, first_name FROM person
WHERE last_name = "John" AND first_name LIKE "J%"

Nhưng người sau sẽ không

SELECT last_name, first_name FROM person WHERE first_name = "Constantine"

Bởi vì bạn đang truy vấn first_namecột trước và nó không phải là cột ngoài cùng bên trái trong chỉ mục.

Ví dụ cuối cùng này thậm chí còn tồi tệ hơn:

SELECT last_name, first_name FROM person WHERE first_name LIKE "%Constantine"

Bởi vì bây giờ, bạn đang so sánh phần ngoài cùng bên phải của trường ngoài cùng bên phải trong chỉ mục.

Chỉ số băm

Đây là một loại chỉ mục khác mà thật không may, chỉ hỗ trợ bộ nhớ phụ trợ. Nó nhanh như chớp nhưng chỉ hữu ích cho việc tra cứu đầy đủ, điều đó có nghĩa là bạn không thể sử dụng nó cho các hoạt động như >, <hoặc LIKE.

Vì nó chỉ hoạt động cho phần cuối bộ nhớ, nên có lẽ bạn sẽ không sử dụng nó thường xuyên. Trường hợp chính tôi có thể nghĩ ra ngay bây giờ là trường hợp bạn tạo một bảng tạm thời trong bộ nhớ với một tập hợp kết quả từ một lựa chọn khác và thực hiện rất nhiều lựa chọn khác trong bảng tạm thời này bằng cách sử dụng các chỉ mục băm.

Nếu bạn có một VARCHARtrường lớn , bạn có thể "mô phỏng" việc sử dụng chỉ mục băm khi sử dụng B-Tree, bằng cách tạo một cột khác và lưu một hàm băm của giá trị lớn trên đó. Giả sử bạn đang lưu trữ một url trong một trường và các giá trị khá lớn. Bạn cũng có thể tạo một trường số nguyên được gọi url_hashvà sử dụng hàm băm như CRC32hoặc bất kỳ hàm băm nào khác để băm url khi chèn nó. Và sau đó, khi bạn cần truy vấn giá trị này, bạn có thể làm một cái gì đó như thế này:

SELECT url FROM url_table WHERE url_hash=CRC32("http://gnu.org");

Vấn đề với ví dụ trên là do CRC32hàm tạo ra một hàm băm khá nhỏ, bạn sẽ kết thúc với rất nhiều xung đột trong các giá trị được băm. Nếu bạn cần các giá trị chính xác, bạn có thể khắc phục sự cố này bằng cách thực hiện như sau:

SELECT url FROM url_table 
WHERE url_hash=CRC32("http://gnu.org") AND url="http://gnu.org";

Vẫn có giá trị để băm mọi thứ ngay cả khi số lần va chạm cao vì bạn sẽ chỉ thực hiện so sánh thứ hai (chuỗi một) so với các giá trị băm lặp đi lặp lại.

Thật không may, bằng cách sử dụng kỹ thuật này, bạn vẫn cần phải nhấn bảng để so sánh urltrường.

Gói (lại

Một số sự thật mà bạn có thể xem xét mỗi khi bạn muốn nói về tối ưu hóa:

  1. So sánh số nguyên là cách nhanh hơn so với so sánh chuỗi. Nó có thể được minh họa bằng ví dụ về mô phỏng chỉ số băm trong InnoDB.

  2. Có thể, thêm các bước bổ sung trong một quy trình làm cho nó nhanh hơn, không chậm hơn. Nó có thể được minh họa bằng việc bạn có thể tối ưu hóa SELECTbằng cách chia nó thành hai bước, tạo giá trị lưu trữ đầu tiên trong bảng trong bộ nhớ mới được tạo, sau đó thực hiện các truy vấn nặng hơn trên bảng thứ hai này.

MySQL cũng có các chỉ mục khác, nhưng tôi nghĩ B + Tree one được sử dụng nhiều nhất từ ​​trước đến nay và hàm băm là một điều tốt để biết, nhưng bạn có thể tìm thấy các chỉ mục khác trong tài liệu MySQL .

Tôi đặc biệt khuyên bạn nên đọc cuốn sách "MySQL hiệu suất cao", câu trả lời ở trên chắc chắn dựa trên chương của nó về các chỉ mục.


2
Các truy vấn sau đây có lợi thế trong trường hợp trên không? 1. SELECT last_name, first_name FROM person WHERE last_name= "Constantine" 2.SELECT last_name, first_name FROM person WHERE last_name LIKE "%Constantine"
Akshay Taru

1
Querry đầu tiên sẽ, truy vấn thứ hai sẽ không. Sử dụng EXPLAIN: dev.mysql.com/doc/refman/5.5/en/explain.html Để lập chỉ mục truy vấn thứ hai với MySQL, bạn phải sử dụng FULLTEXT
Emilio Nicolás

5
Tôi đánh giá cao bạn vì bạn ở mức 127 và câu trả lời số 1 là 256. Tôi không thể tránh làm cho mọi thứ trở nên tốt đẹp và sạch sẽ, thông minh nhị phân.
pbarney

Đây là thông tin mới cho tôi "yêu cầu bạn truy vấn các lĩnh vực này rất nhiều." cảm ơn.
Khatri

1
@pbarney sau ba năm lần lượt là gần 256 và 512, đó là điều tôi gọi là sự gia tăng khôn ngoan nhị phân!
nanocv

43

Về cơ bản một chỉ mục là bản đồ của tất cả các khóa của bạn được sắp xếp theo thứ tự. Với một danh sách theo thứ tự, sau đó thay vì kiểm tra mọi khóa, nó có thể làm một cái gì đó như thế này:

1: Đi đến giữa danh sách - cao hơn hoặc thấp hơn những gì tôi đang tìm kiếm?

2: Nếu cao hơn, đi đến điểm giữa giữa và dưới, nếu thấp hơn, giữa và trên cùng

3: Là cao hơn hay thấp hơn? Nhảy đến điểm giữa một lần nữa, v.v.

Sử dụng logic đó, bạn có thể tìm thấy một yếu tố trong danh sách được sắp xếp theo khoảng 7 bước, thay vì kiểm tra mọi mục.

Rõ ràng có những phức tạp, nhưng điều đó cho bạn ý tưởng cơ bản.


29
Đây được gọi là tìm kiếm nhị phân.
ddlshack

Cảm ơn, cuối cùng là một câu trả lời giải thích tại sao nó nhanh hơn và không chỉ là cách các hàm db với các chỉ mục.
Gershon Herczeg

Số bước thực tế phụ thuộc nhiều vào dữ liệu - số lượng giá trị và phân phối duy nhất trong phạm vi của bạn. 7 là tối đa lý thuyết cho 100 giá trị. Thảo luận đầy đủ về cách tính số bước ở đây stackoverflow.com/questions/10571170/iêu
Joshua

Chỉ mục MySQL phổ biến nhất là Cây B + hoạt động tương tự như tìm kiếm nhị phân nhưng không hoàn toàn giống nhau. Độ phức tạp thuật toán là như nhau nhưng cách nó tìm kiếm thì không. Xem en.wikipedia.org/wiki/B-tree
Matt

4

Hãy xem liên kết này: http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html

Làm thế nào họ làm việc là quá rộng của một chủ đề để bao quát trong một bài SO.

Đây là một trong những giải thích tốt nhất về các chỉ số tôi đã thấy. Thật không may, nó là dành cho SQL Server chứ không phải MySQL. Tôi không chắc hai người giống nhau đến thế nào ...


2
Bài viết hay. Tôi không biết SQL Server, nhưng các hoạt động cơ bản trông rất giống nhau. (metanote: vô hiệu hóa các kiểu CSS trong bài viết được liên kết thứ 2 không che giấu nội dung)
Piskvor rời khỏi tòa nhà vào

3

Xem video này để biết thêm chi tiết về Lập chỉ mục

Lập chỉ mục đơn giản Bạn có thể tạo một chỉ mục duy nhất trên bảng. Một chỉ mục duy nhất có nghĩa là hai hàng không thể có cùng giá trị chỉ mục. Đây là cú pháp để tạo một Index trên bảng

CREATE UNIQUE INDEX index_name
ON table_name ( column1, column2,...);

Bạn có thể sử dụng một hoặc nhiều cột để tạo chỉ mục. Ví dụ: chúng ta có thể tạo một chỉ mục tutorials_tblbằng cách sử dụng hướng dẫn.

CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author)

Bạn có thể tạo một chỉ mục đơn giản trên một bảng. Chỉ cần bỏ qua từ khóa UNIITE từ truy vấn để tạo chỉ mục đơn giản. Chỉ mục đơn giản cho phép các giá trị trùng lặp trong một bảng.

Nếu bạn muốn lập chỉ mục các giá trị trong một cột theo thứ tự giảm dần, bạn có thể thêm từ dành riêng DESC sau tên cột.

mysql> CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author DESC)

1
Chào mừng bạn đến với Stack Overflow! Tôi đã lưu ý rằng tất cả các câu trả lời của bạn liên kết đến video của riêng bạn. Xin lưu ý rằng tự quảng cáo quá mức không được phép .
SL Barth - Phục hồi Monica

Anh ấy muốn quảng bá video của mình. LOL
Ilyas karim

1

Tôi muốn thêm 2 xu của tôi. Tôi không phải là một chuyên gia cơ sở dữ liệu, nhưng gần đây tôi đã đọc một chút về chủ đề này; đủ để tôi thử và đưa ra ELI5. Vì vậy, đây là lời giải thích của giáo dân.


Tôi hiểu rằng một chỉ mục giống như một tấm gương nhỏ của bảng của bạn, gần giống như một mảng kết hợp. Nếu bạn cung cấp nó bằng một khóa khớp thì bạn có thể chỉ cần nhảy đến hàng đó trong một "lệnh".

Nhưng nếu bạn không có chỉ mục / mảng đó, trình thông dịch truy vấn phải sử dụng vòng lặp for để đi qua tất cả các hàng và kiểm tra sự trùng khớp (quét toàn bộ bảng).

Có một chỉ mục có "nhược điểm" của bộ nhớ bổ sung (đối với gương nhỏ đó), để đổi lấy "mặt trái" của việc tra cứu nội dung nhanh hơn.

Lưu ý rằng (phụ thuộc vào công cụ db của bạn) tạo các khóa chính, khóa ngoài hoặc duy nhất cũng tự động thiết lập một chỉ mục tương ứng. Nguyên tắc tương tự về cơ bản là tại sao và làm thế nào các phím đó hoạt động.


1

Thêm một số đại diện trực quan vào danh sách các câu trả lời. nhập mô tả hình ảnh ở đây

MySQL sử dụng một lớp bổ sung bổ sung: các bản ghi chỉ mục phụ chỉ vào các bản ghi chỉ mục chính và chính chỉ mục chính giữ các vị trí hàng trên đĩa. Nếu một hàng bù thay đổi, chỉ có chỉ số chính cần được cập nhật.

Hãy cẩn thận: Cấu trúc dữ liệu đĩa trông phẳng trong sơ đồ nhưng thực sự là cây B +.

Nguồn: liên kết


1

Trong MySQL InnoDB, có hai loại chỉ mục.

  1. Khóa chính được gọi là chỉ mục cụm. Các từ khóa chỉ mục được lưu trữ với dữ liệu ghi thực trong nút lá B + Tree.

  2. Khóa phụ là chỉ mục không cụm. Các chỉ mục này chỉ lưu trữ các từ khóa của khóa chính cùng với các từ khóa chỉ mục riêng của chúng trong nút lá B + Tree. Vì vậy, khi tìm kiếm từ chỉ mục phụ, trước tiên, nó sẽ tìm thấy các từ khóa chính của chỉ mục chính và quét khóa chính B + Tree để tìm các bản ghi dữ liệu thực. Điều này sẽ làm cho chỉ mục phụ chậm hơn so với tìm kiếm chỉ mục chính. Tuy nhiên, nếu các selectcột đều nằm trong chỉ mục phụ, thì không cần phải tìm lại chỉ mục chính B + Tree nữa. Điều này được gọi là chỉ số bao gồm.

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.