Bảo trì chỉ mục MySQL


12

Tôi đã thực hiện rất nhiều nghiên cứu về cách duy trì các chỉ mục trong MySQL để ngăn chặn sự phân mảnh và tối ưu hóa bằng cách nào đó thực hiện một số truy vấn.

Tôi quen thuộc với công thức đó tính toán tỷ lệ giữa không gian tối đa có sẵn cho một bảng VS không gian được sử dụng bởi dữ liệu và chỉ mục.

Tuy nhiên, câu hỏi chính của tôi vẫn chưa được trả lời. Có lẽ điều này là do thực tế là tôi đã quen với việc bảo trì chỉ mục trong SQL Server và tôi có xu hướng nghĩ rằng trong MySQL nó phải giống nhau.

Trong máy chủ SQL, bạn có thể có một vài chỉ mục và mỗi chỉ mục có thể có các mức phân mảnh khác nhau. Sau đó, bạn có thể chọn một và thực hiện thao tác 'REORGANIZE' hoặc 'REBUILD' trong chỉ mục cụ thể đó mà không ảnh hưởng đến phần còn lại.

Theo hiểu biết tốt nhất của tôi, không có 'phân mảnh bảng' như vậy và SQL Server không cung cấp bất kỳ công cụ nào để khắc phục 'phân mảnh bảng'. Những gì nó cung cấp là các công cụ để kiểm tra phân mảnh chỉ mục (được hiểu như tỷ lệ giữa số lượng trang được sử dụng bởi một chỉ mục VS mức độ đầy đủ của trang đó và sự liên tục), cũng như phân mảnh bên trong và bên ngoài.

Tất cả điều đó khá đơn giản để hiểu, ít nhất là đối với tôi.

Bây giờ, khi đến lượt duy trì các chỉ mục trong MySQL, chỉ tồn tại khái niệm 'phân mảnh bảng, như đã đề cập ở trên.

Một bảng trong MySQL có thể có một vài chỉ mục, nhưng khi tôi kiểm tra 'tỷ lệ phân mảnh' với công thức nổi tiếng đó, tôi không thấy sự phân mảnh của từng chỉ mục, mà là toàn bộ bảng.

Khi tôi muốn tối ưu hóa các chỉ mục trong MySQL, tôi không chọn một chỉ mục cụ thể để hoạt động (như trong SQL Server). Thay vào đó, tôi thực hiện thao tác 'TỐI ƯU HÓA' trong toàn bộ bảng, điều này có lẽ ảnh hưởng đến tất cả các chỉ mục.

Khi bảng được tối ưu hóa trong MySQL, tỷ lệ giữa không gian được sử dụng bởi dữ liệu + chỉ mục VS không gian tổng thể bị giảm, điều này cho thấy một số loại tổ chức lại vật lý trong ổ cứng, giúp chuyển thành giảm không gian vật lý. Tuy nhiên, phân mảnh chỉ mục không chỉ về không gian vật lý, mà cấu trúc của cây đã bị thay đổi theo thời gian do chèn và cập nhật.

Cuối cùng, tôi đã nhận được một bảng trong InnoDB / MySQL. Bảng đó có 3 triệu bản ghi, 105 cột và 55 chỉ mục. Đó là 1,5 GB không bao gồm các chỉ mục, là 2,1 GB.

Bảng đó đang được nhấn hàng ngàn lần mỗi ngày để cập nhật, chèn (chúng tôi không thực sự xóa các bản ghi).

Bảng đó đã được tạo ra trong nhiều năm và tôi biết chắc chắn rằng không ai duy trì chỉ số nào.

Tôi đã mong đợi để tìm thấy một sự phân mảnh lớn trong đó, nhưng khi tôi thực hiện tính toán phân mảnh theo quy định

free_space / (data_length + index_length)

Hóa ra tôi chỉ có phân mảnh 0,2%. IMHO đó là khá phi thực tế.

Vì vậy, những câu hỏi lớn là:

  1. Làm cách nào để kiểm tra sự phân mảnh của một chỉ mục cụ thể trong MySQL, chứ không phải toàn bộ bảng
  2. Liệu TỐI ƯU BẢNG có thực sự khắc phục sự phân mảnh bên trong / bên ngoài của một chỉ mục như trong SQL Server không?
  3. Khi tôi tối ưu hóa một bảng trong MySQL, nó có thực sự xây dựng lại tất cả các chỉ mục trên bảng không?
  4. Có thực tế không khi nghĩ rằng việc giảm không gian vật lý của một chỉ mục (mà không xây dựng lại chính cây) thực sự chuyển thành một hiệu suất tốt hơn?

bảng tối ưu hóa chắc chắn dọn sạch chỉ số được nhóm trên innodb

1
đó là một câu hỏi hay, không phải là một câu hỏi lập trình. Sẽ được chuyển đến nơi thuộc về:>

Câu trả lời:


6

Phân mảnh chỉ số được đánh giá cao hơn nhiều. Đừng lo về nó.

Hai khối liền kề, có phần trống rỗng, được InnoDB sáp nhập với nhau như là quá trình xử lý tự nhiên.

Các hành động ngẫu nhiên trên BTree khiến nó tự nhiên bị hút về mức trung bình 69%. Chắc chắn, điều này không phải là 100%, nhưng chi phí "sửa chữa" là không đáng.

SHOW TABLE STATUS cung cấp cho bạn một số số liệu, nhưng chúng còn thiếu sót - "Data_free" bao gồm không gian "miễn phí" nhất định, nhưng không phải là không gian "miễn phí" khác.

Có không gian chưa sử dụng trong mỗi khối; khối 16KB miễn phí; "phạm vi" miễn phí (khối nMB); Hàng MVCC đang chờ để được gặt hái; hạch không lá có sự phân mảnh riêng của chúng; Vân vân.

Percona và Oracle có những cách khác nhau để xem mức độ lớn (số khối) của một chỉ mục. Tôi thấy cả hai đều không hữu ích vì định nghĩa hạn chế của "miễn phí". Dường như các khối (mỗi khối 16KB) được phân bổ theo khối (vài MB), do đó khiến người ta tin rằng có tất cả các loại phân mảnh. Trong thực tế, nó thường chỉ là một trong những khối nhiều MB này. Và OPTIMIZE TABLEkhông nhất thiết phải bù lại bất kỳ không gian.

Nếu SQL Server đang sử dụng BTrees, thì sẽ nói dối rằng "không có sự phân mảnh". Hãy nghĩ về những gì xảy ra trên một "tách khối". Hoặc nghĩ về chi phí liên tục chống phân mảnh. Dù bằng cách nào bạn cũng thua.

Lưu ý thêm rằng một bảng và một chỉ mục về cơ bản là các cấu trúc giống nhau:

  • B + Tree, dựa trên một số chỉ số
  • "Dữ liệu" được dựa trên KHÓA CHÍNH; mỗi chỉ số phụ là một cây B + dựa trên chỉ số của nó.
  • Nút lá của "dữ liệu" chứa tất cả các cột của bảng.
  • Nút lá của một chỉ mục phụ chứa các cột của chỉ mục phụ đó, cộng với các cột của KHÓA CHÍNH.

Nếu bạn có innodb_file_per_table = ON, bạn có thể thấy rõ độ co rút (nếu có) sau khi TỐI ƯU BẢNG bằng cách xem .ibdkích thước của tệp. Đối với OFF, thông tin được chôn trong ibdata1, nhưng SHOW TABLE STATUScó thể chính xác một cách hợp lý vì tất cả không gian "miễn phí" thuộc về mỗi bảng. Vâng, ngoại trừ các khối được phân bổ trước.

Bạn có thể nhận thấy rằng một bảng mỗi bảng được tối ưu hóa mới có chính xác 4M, 5M, 6M hoặc 7 giây của Data_free. Một lần nữa, đây là phân bổ trước, và không cung cấp cho bạn các chi tiết phút.

Tôi đã làm việc với InnoDB trong hơn một thập kỷ; Tôi đã làm việc với hàng ngàn bảng khác nhau, lớn và nhỏ. Tôi nói rằng chỉ có một bảng trong một ngàn thực sự cần OPTIMIZE TABLE. Sử dụng nó trên các bảng khác là một sự lãng phí.

105 cột là rất nhiều, nhưng có lẽ không quá nhiều.

Bạn có 55 chỉ mục trên một bảng? Thật tệ. Đó là 55 cập nhật mỗi INSERT. Hãy thảo luận thêm. Hãy nhớ rằng đó INDEX(a)là vô ích nếu bạn cũng có INDEX(a,b). Và INDEX(flag)là vô dụng vì cardinality thấp. (Nhưng INDEX(flag, foo)có thể hữu ích.)

Q1: Không có cách nào tốt để kiểm tra tất cả các dạng phân mảnh trong dữ liệu hoặc chỉ mục phụ.

Q2, Q3: OPTIMIZE TABLExây dựng lại bảng bằng CREATEingmột bảng mới và INSERTingtất cả các hàng, sau đó RENAMEingDROPping. Việc chèn lại dữ liệu theo thứ tự PK đảm bảo dữ liệu được phân mảnh tốt. Các chỉ số là một vấn đề khác.

Q4: Bạn có thể DROPreCREATEtừng chỉ số để dọn sạch nó. Nhưng đây là một quá trình cực kỳ chậm. 5.6 có một số tăng tốc, nhưng tôi không biết liệu chúng có giúp chống phân mảnh hay không.

Nó cũng có thể ALTER TABLE ... DISABLE KEYS, sau đó ENABLEhọ. Điều này có thể để xây dựng lại hiệu quả hơn của tất cả các chỉ mục phụ cùng một lúc.


Rick, ý tôi là các trường '105', không phải tệp
Nicolas

1

Làm cách nào để kiểm tra sự phân mảnh của một chỉ mục cụ thể trong MySQL, chứ không phải toàn bộ bảng

Vượt qua.

Liệu TỐI ƯU BẢNG có thực sự khắc phục sự phân mảnh bên trong / bên ngoài của một chỉ mục như trong SQL Server không?

Nó xây dựng lại hoàn toàn bảng và các chỉ mục của nó.

Khi tôi tối ưu hóa một bảng trong MySQL, nó có thực sự xây dựng lại tất cả các chỉ mục trên bảng không?

Đó là cùng một câu hỏi với cùng một câu trả lời.

Có thực tế không khi nghĩ rằng việc giảm không gian vật lý của một chỉ mục (mà không xây dựng lại chính cây) thực sự chuyển thành một hiệu suất tốt hơn?

Thật không thực tế khi nghĩ rằng bạn có thể giảm không gian mà không cần xây dựng lại cây. Họ đi cùng nhau.


Để trả lời # 1: Mặc dù nó không chính xác lắm, nhưng SHOW TABLE STATUS LIKE 'mytable'sẽ đưa ra một gợi ý trong data freecột. dev.mysql.com/doc/refman/5.6/en/show-table-status.html
Jehad Keriaki

Tôi biết, nhưng điều đó vẫn còn thiếu không gian của một chỉ số cụ thể
Nicolas
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.