Cách tìm và sửa các bảng MySQL bị phân mảnh


27

Tôi đã sử dụng MySQLTuner chỉ ra một số bảng bị phân mảnh. Tôi đã sử dụng

mysqlcheck - tối đa hóa -A

để tối ưu hóa tất cả các bảng. Nó đã sửa một số bảng nhưng MySQLTuner vẫn tìm thấy 19 bảng bị phân mảnh. Làm thế nào tôi có thể thấy bảng nào đang cần chống phân mảnh? Có lẽ TỐI ƯU BẢNG sẽ hoạt động ở nơi mysqlcheck không? Hoặc những gì khác tôi nên thử?


1
Tôi có một vấn đề tương tự. Tôi đang thiết lập một DB mới với MySQL 5.5 và một số bảng InnoDB nhất định không bao giờ gây khó chịu. Tôi tự hỏi nếu kiểm tra Data_free (được hiển thị trong câu trả lời của kayJim) không chính xác với các bảng InnoDB.
docwhat

Câu trả lời:


38

Câu trả lời ngắn gọn:

select  ENGINE, TABLE_NAME,Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free from information_schema.tables  where  DATA_FREE > 0;

Câu trả lời "Bạn phải biết"

trước hết bạn phải hiểu rằng các bảng Mysql bị phân mảnh khi một hàng được cập nhật, vì vậy đó là một tình huống bình thường. Khi một bảng được tạo, giả sử được nhập bằng cách sử dụng kết xuất dữ liệu, tất cả các hàng được lưu trữ không có phân mảnh trong nhiều trang có kích thước cố định. Khi bạn cập nhật một hàng có chiều dài thay đổi, trang chứa hàng này được chia thành hai hoặc nhiều trang để lưu trữ các thay đổi và hai trang mới (hoặc nhiều hơn) này chứa các khoảng trống lấp đầy khoảng trống không sử dụng.

Điều này không ảnh hưởng đến hiệu suất, trừ khi tất nhiên sự phân mảnh tăng quá nhiều. Quá nhiều phân mảnh, hãy xem truy vấn bạn đang tìm kiếm:

  select  ENGINE, TABLE_NAME,Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free from information_schema.tables  where  DATA_FREE > 0;

DATA_LENGTH và INDEX_LENGTH là không gian mà dữ liệu và chỉ mục của bạn đang sử dụng và DATA_FREE là tổng số byte không được sử dụng trong tất cả các trang của bảng (phân mảnh).

Đây là một ví dụ về một bảng sản xuất thực sự

| ENGINE | TABLE_NAME               | data_length | index_length | data_free |
| InnoDB | comments                 |         896 |          316 |         5 |

Trong trường hợp này, chúng tôi có Bảng sử dụng (896 + 316) = 1212 MB và có dữ liệu không gian trống là 5 MB. Điều này có nghĩa là "tỷ lệ phân mảnh" của:

5/1212 = 0.0041

... Đó là một "tỷ lệ phân mảnh" thực sự thấp.

Tôi đã làm việc với các bảng có tỷ lệ gần 0,2 (nghĩa là 20% khoảng trống) và không bao giờ nhận thấy sự chậm lại của các truy vấn, ngay cả khi tôi tối ưu hóa bảng, hiệu suất vẫn như nhau. Nhưng áp dụng bảng tối ưu hóa trên bảng 800 MB sẽ mất rất nhiều thời gian và chặn bảng trong vài phút, điều này không thể thực hiện được trong quá trình sản xuất.

Vì vậy, nếu bạn xem xét những gì bạn giành được trong hiệu suất và thời gian lãng phí trong việc tối ưu hóa một bảng, tôi không thích tối ưu hóa.

Nếu bạn nghĩ rằng tốt hơn cho việc lưu trữ, hãy xem tỷ lệ của bạn và xem bạn có thể tiết kiệm được bao nhiêu dung lượng khi tối ưu hóa. Nó thường không quá nhiều, vì vậy tôi không thích tối ưu hóa.

Và nếu bạn tối ưu hóa, bản cập nhật tiếp theo sẽ tạo khoảng trắng bằng cách chia một trang thành hai hoặc nhiều hơn. Nhưng cập nhật bảng phân mảnh nhanh hơn bảng không phân mảnh, vì nếu bảng bị phân mảnh, bản cập nhật trên một hàng không nhất thiết sẽ chia một trang.

Tôi hy vọng cái này sẽ giúp bạn.


1
Mặc dù đây là câu trả lời từ vài năm trước, tôi nghĩ rằng tôi đã chỉ ra rằng data_free là một chỉ số cho toàn bộ không gian bảng, không phải cho bảng tương ứng. Nếu bạn lưu trữ nhiều bảng với nhau trong một không gian bảng, data_free có thể khiến bạn hiểu rằng bảng cần chống phân mảnh, khi đó chỉ có nghĩa là có các khoảng trống miễn phí trong không gian bảng. Chạy tối ưu hóa bảng sẽ không làm giảm mức độ miễn phí. Chống phân mảnh bảng thậm chí có thể làm tăng phạm vi miễn phí.
Bill Karwin

14

Chỉ cần thêm vào câu trả lời từ Felipe-Rojas, bạn có thể tính tỷ lệ phân đoạn như một phần của truy vấn:

select ENGINE,
  concat(TABLE_SCHEMA, '.', TABLE_NAME) as table_name,
  round(DATA_LENGTH/1024/1024, 2) as data_length,
  round(INDEX_LENGTH/1024/1024, 2) as index_length,
  round(DATA_FREE/1024/1024, 2) as data_free,
  (data_free/(index_length+data_length)) as frag_ratio
FROM information_schema.tables
WHERE DATA_FREE > 0
ORDER BY frag_ratio DESC;

Nếu một bảng bị phân mảnh một tỷ lệ nhỏ (dưới 5%?) Thì có lẽ bạn có thể để nó một mình.

Bất cứ điều gì lớn hơn và bạn sẽ cần phải đánh giá dựa trên việc sử dụng db của bạn, khóa các bảng, v.v ... về tầm quan trọng của việc chống phân mảnh bảng.


2

Bảng tối ưu hóa thực sự sẽ giải quyết vấn đề bạn đang gặp phải.

Nếu bạn chỉ có một vài cơ sở dữ liệu, thì bạn có thể sử dụng PHPMyAdmin để duyệt qua tất cả các cơ sở dữ liệu của mình. Chọn các bảng có phí và sau đó chọn để tối ưu hóa.

Nếu bạn có nhiều cơ sở dữ liệu thì phương pháp khác có thể sẽ thích hợp hơn.

Tôi sử dụng thiết lập tập lệnh PHP sau trong cron để chạy mỗi giờ.

$DB = new mysqli ('localhost', 'DbUser', 'DbPassword');
$results = $DB->query('show databases');
$allDbs = array();
while ($row = $results->fetch_array(MYSQLI_NUM))
{
    $allDbs[] = $row[0];
}
$results->close();
foreach ($allDbs as $dbName)
{
    if ($dbName != 'information_schema' && $dbName != 'mysql')
    {
        $DB->select_db($dbName);
        $results = $DB->query('SHOW TABLE STATUS WHERE Data_free > 0');
        if ($results->num_rows > 0)
        {
            while ($row = $results->fetch_assoc())
            {
                $DB->query('optimize table ' . $row['Name']);
            }
        }
        $results->close();
    }
}
$DB->close();

3
Tôi khá chắc chắn rằng mysqlcheck --optimize -Anó giống như SQLOPTIMIZE TABLE <tablename>;
docwhat

2

Tôi đã xem qua trang này và thấy các truy vấn của Felipe-Rojas và sysadmirus rất hữu ích. Nhưng trong trường hợp của tôi, tôi đã chạy truy vấn trong phpMyAdmin của WHM và chỉ nhận TABLE_NAME là không hữu ích vì cơ sở dữ liệu không được liệt kê và một số cơ sở dữ liệu có cùng tên bảng. Vì vậy, chỉ cần thêm TABLE_SCHEMAsẽ cung cấp cột đó là tốt.

select  ENGINE, TABLE_SCHEMA, TABLE_NAME, Round( DATA_LENGTH/1024/1024) as data_length , round(INDEX_LENGTH/1024/1024) as index_length, round(DATA_FREE/ 1024/1024) as data_free, (data_free/(index_length+data_length)) as frag_ratio from information_schema.tables  where  DATA_FREE > 0 order by frag_ratio desc

Hiển thị DB

ENGINE  | TABLE_SCHEMA  | TABLE_NAME    | data_length   | index_length  | data_free | frag_ratio

InnoDB  | db_name       | db_table      | 0             | 0             | 8         | 170.6667

Để "sửa lỗi", tôi đã sử dụng liên kết bảng Defragment trong phpMyAdmin cho mỗi bảng dẫn đến "Frag_ratio" cao mà phpMyAdmin thực thi:

ALTER TABLE `table_name` ENGINE = InnoDB;

0

Một bảng sử dụng InnoDB Engine của MySQL về cơ bản không bao giờ cần phải có OPTIMIZEd.

Giá trị của Data_freemột trong hai information_schema.tableshoặc SHOW TABLE STATUSrất thường là khác không, ngay cả khi bạn nghĩ rằng bạn đã làm tất cả những gì bạn có thể làm để chống phân mảnh (các) bảng của bạn. Hơn nữa, số liệu đó chỉ là một trong một số phân đoạn có thể và có thể xảy ra. (Ngoài ra, lãng phí không gian trong các khối, hoàn tác danh sách, chỉ số BTrees so với BTrees dữ liệu, v.v.

innodb_file_per_tablelàm phức tạp việc sử dụng Data_free. Nếu bảng nằm trong ibdata1, thì Data_freetham chiếu đến toàn bộ không gian bảng; một con số khá vô dụng. Nếu bảng nằm trong .ibdtệp riêng của nó, nó có thể là một vài MB hoặc một vài phần trăm kích thước của bảng, tùy theo giá trị nào lớn hơn.

Chỉ khi bạn đã xóa rất nhiều hàng không có ý định làm lại bàn, có thể nó có giá trị chạy OPTIMIZE TABLE.

PARTITIONscũng hiển thị số lượng đáng lo ngại Data_free, vì mỗi phân vùng thường hiển thị 4-7 MB "miễn phí". Và điều này sẽ không biến mất.

Tại sao phải chống phân mảnh?

  • Để trả lại không gian cho hệ điều hành? Vâng, bạn có thể đạt được điều này một thời gian ngắn nếu bạn có innodb_file_per_table=1. Nhưng khi bạn thêm hàng, bạn sẽ lấy lại từ HĐH.
  • Để tăng tốc truy cập? Quên đi. Bố cục của các khối trên đĩa là tương đối ngẫu nhiên, và đã được trong vài thập kỷ qua. Nửa thế kỷ trước, việc sắp xếp lại các khối là điều quan trọng.
  • Để cân bằng lại BTrees? Vì thế? Họ sẽ nhanh chóng trở nên mất cân bằng một lần nữa. Trạng thái ổn định cho BTrees được chèn ngẫu nhiên vào là 69%. Và điều đó thậm chí không được tính vào Data_free.
  • MySQLTuner nói với? Sản phẩm đó cần được làm lạnh.

Một ghi chú lịch sử. Khi tôi đang giúp các DBA với hầu hết các bảng MyISAM, tôi phát hiện ra có lẽ 2 trong số 1000 bảng được trợ giúp hàng tháng OPTIMIZE . Kể từ đó, tôi đã làm việc với hàng ngàn bảng InnoDB, vẫn chưa tìm thấy vấn đề về hiệu năng có thể được trợ giúp OPTIMIZE. (Chắc chắn, đã có vấn đề về không gian đĩa OPTIMIZEcó thể giúp ích, nhưng điều đó trở nên khó khăn - thường thì DBA không có đủ dung lượng đĩa để chạy OPTIMIZE!)

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.