2010-05-26 40 views
7

Tôi đang cố gắng tìm ra các yêu cầu bộ nhớ cho các công cụ lưu trữ khác nhau. Tôi có bảng này:Tại sao kích thước bảng InnoDB lớn hơn nhiều so với dự kiến?

CREATE TABLE `mytest` (
    `num1` int(10) unsigned NOT NULL, 
    KEY `key1` (`num1`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

Khi tôi chèn một số giá trị và sau đó chạy show table status; tôi nhận được như sau:

 
+----------------+--------+---------+------------+---------+----------------+-------------+------------------+--------------+-----------+----------------+---------------------+---------------------+------------+-------------------+----------+----------------+---------+ 
| Name   | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time   | Update_time   | Check_time | Collation   | Checksum | Create_options | Comment | 
+----------------+--------+---------+------------+---------+----------------+-------------+------------------+--------------+-----------+----------------+---------------------+---------------------+------------+-------------------+----------+----------------+---------+ 
| mytest   | InnoDB |  10 | Compact | 1932473 |    35 | 67715072 |    0 |  48840704 | 4194304 |   NULL | 2010-05-26 11:30:40 | NULL    | NULL  | latin1_swedish_ci |  NULL |    |   | 

Thông báo avg_row_length là 35. Tôi đang bối rối mà InnoDB sẽ không tận dụng tốt hơn về không gian khi tôi chỉ lưu trữ một số nguyên không nullable.

Tôi đã chạy thử nghiệm tương tự này trên myISAM và theo mặc định, myISAM sử dụng 7 byte mỗi hàng trên bảng này. Khi tôi chạy

ALTER TABLE mytest MAX_ROWS=50000000, AVG_ROW_LENGTH = 4; 

làm cho myISAM cuối cùng sử dụng chính xác các hàng 5 byte.

Khi tôi chạy cùng một câu lệnh ALTER TABLE cho InnoDB thì avg_row_length không thay đổi.

Tại sao avg_row_length lớn này lại cần thiết khi chỉ lưu trữ int không dấu 4 byte?

+0

Tôi chỉ đọc rằng InnoDB sử dụng không gian bảng cho cả dữ liệu và chỉ mục. điều này có ý nghĩa và có vẻ như đây là lý do tại sao tôi thấy một avg_row_length lớn ... có thể. Tôi cũng phát hiện ra rằng mỗi nút lá lưu trữ ID giao dịch và con trỏ rollback. Vâng, tôi không sử dụng các giao dịch cho mỗi lần và do đó không sử dụng cho dữ liệu này. có cách nào để không lưu trữ các giá trị này không? Bất kỳ cách nào tôi có thể sử dụng InnoDB nhưng làm cho một chút tốt hơn sử dụng lưu trữ? cảm ơn! –

+0

@alessandro: có, hỗ trợ giao dịch cũng làm tăng thêm một số chi phí. Thực tế là bạn không sử dụng các giao dịch không có nghĩa là chúng không được sử dụng: ví dụ, một chuỗi bị giết trong quá trình hoạt động 'UPDATE' dài sẽ quay lại chính xác trong' InnoDB' nhưng không phải trong 'MyISAM'. Hỗ trợ giao dịch là toàn bộ điểm sử dụng 'InnoDB', nếu bạn không cần nó, chỉ cần sử dụng' MyISAM'. – Quassnoi

+0

@Quassnoi: Tôi có ấn tượng rằng MyISAM không phải là "trưởng thành" hoặc sản xuất đã sẵn sàng như InnoDB ... có lẽ đó là một nỗi sợ hãi vô căn cứ. Có bất kỳ khó khăn nào mà MyISAM mang đến khi nói đến việc sao lưu cơ sở dữ liệu ngoài thực tế là MyISAM yêu cầu khóa bàn đầy đủ để đảm bảo tính nhất quán. Tôi không yêu cầu giao dịch và tôi sẽ lưu trữ rất nhiều dữ liệu. Có bất kỳ vấn đề đã biết với MyISAM có thể khiến bạn không sử dụng nó không? –

Trả lời

10

InnoDB bảng được nhóm lại, điều đó có nghĩa là tất cả dữ liệu được chứa trong một B-Tree với PRIMARY KEY làm khóa và tất cả các cột khác làm trọng tải.

Vì bạn không xác định rõ ràng PRIMARY KEY, InnoDB sử dụng cột 6 byte ẩn để sắp xếp các bản ghi.

Điều này và chi phí của tổ chức B-Tree (với các khối không cao hơn lá) yêu cầu nhiều không gian hơn sizeof(int) * num_rows.

0

Ngoài câu trả lời rất hay của Quassnoi, bạn có lẽ nên dùng thử một bộ dữ liệu quan trọng.

Điều tôi muốn làm là tải 1M hàng dữ liệu sản xuất mô phỏng vào, sau đó đo kích thước bảng và sử dụng làm hướng dẫn.

Đó là những gì I've done in the past anyway

+0

Vâng, cảm ơn MarkR, tôi đã làm điều này với một tập hợp dữ liệu gồm 50 triệu hàng. InnoDB sử dụng không gian nhiều hơn 3 lần tại 3GIGs –

+0

Dựa trên nghiên cứu của tôi (xem liên kết ở trên), đây là điển hình; bạn có thể sử dụng ít dung lượng hơn bằng cách sử dụng plugin và bật tính năng nén. Xem bài đăng trên blog của tôi để biết một số dữ liệu. – MarkR

2

Dưới đây là một số thông tin khác mà bạn có thể thấy hữu ích.

InnoDB phân bổ dữ liệu theo trang 16KB, vì vậy 'HIỂN THỊ TABLE STATUS' sẽ cung cấp số tăng cho kích thước hàng nếu bạn chỉ có một vài hàng và bảng là tổng số < 16K. (Ví dụ: với 4 hàng, kích thước hàng trung bình quay trở lại là 4096.)

6 byte phụ cho mỗi hàng cho khóa chính "ẩn" là điểm quan trọng khi không gian là một cân nhắc lớn. Nếu bảng của bạn chỉ là một cột, đó là cột lý tưởng để làm khóa chính, giả định các giá trị trong nó là duy nhất:

CREATE TABLE `mytest2` 
     (`num1` int(10) unsigned NOT NULL primary key) 
ENGINE=InnoDB DEFAULT CHARSET=latin1; 

Bằng cách sử dụng một PRIMARY KEY như thế này:

  1. Không INDEX hoặc Mệnh đề KEY là cần thiết, bởi vì bạn không có chỉ mục phụ. Định dạng được tổ chức theo chỉ mục của các bảng InnoDB cung cấp cho bạn tra cứu nhanh dựa trên giá trị khóa chính miễn phí.
  2. Bạn không kết thúc với một bản sao dữ liệu cột NUM1 khác, đó là những gì xảy ra khi cột đó được lập chỉ mục một cách rõ ràng.
  3. Bạn không cần phải sao lưu một bản sao khác của giá trị khóa chính ẩn 6 byte. Các giá trị khóa chính được nhân đôi trong mỗi chỉ mục phụ. (Đó cũng là lý do tại sao bạn có thể không muốn 10 chỉ mục trên một bảng có 10 cột và bạn có thể không muốn một khóa chính kết hợp nhiều cột khác nhau hoặc là cột chuỗi dài.)

Vì vậy, tổng thể, gắn bó với chỉ một khóa chính có nghĩa là ít dữ liệu được liên kết với bảng + chỉ mục. Để có được một cảm giác kích thước dữ liệu tổng thể, tôi muốn chạy với

set innodb_file_per_table = 1; 

và kiểm tra kích thước của dữ liệu/cơ sở dữ liệu file /*table*.ibd. Mỗi tệp .ibd chứa dữ liệu cho một bảng InnoDB và tất cả các chỉ mục liên quan của nó.

Để nhanh chóng xây dựng một bảng lớn để thử nghiệm, tôi thường chạy một tuyên bố như vậy:

insert into mytest 
select * from mytest; 

nào tăng gấp đôi lượng dữ liệu mỗi lần. Trong trường hợp của bảng đơn cột sử dụng một khóa chính, vì các giá trị phải là duy nhất, tôi đã sử dụng một biến thể để giữ các giá trị từ va chạm với nhau:

insert into mytest2 
select num1 + (select count(*) from mytest2) from mytest2; 

Bằng cách này, tôi đã có thể nhận được kích thước hàng trung bình xuống đến 25. Khoảng trống trên không gian dựa trên giả định cơ bản mà bạn muốn tra cứu nhanh các hàng riêng lẻ bằng cách sử dụng cơ chế kiểu con trỏ và hầu hết các bảng sẽ có một cột có giá trị làm con trỏ (ví dụ:) ngoài các cột có dữ liệu thực được tổng hợp, tính trung bình và hiển thị.

+0

Thông tin tuyệt vời tại đây, cảm ơn bạn đã chia sẻ. – dkamins

Các vấn đề liên quan