2010-05-24 36 views
10

Tôi đã sử dụng cơ sở dữ liệu để lưu trữ các mục và thuộc tính về các mục này. Số lượng thuộc tính có thể mở rộng, do đó có một bảng nối để lưu trữ từng thuộc tính được liên kết với một giá trị mục.Làm cách nào để xử lý bảng lớn trong MySQL?

CREATE TABLE `item_property` (
    `property_id` int(11) NOT NULL, 
    `item_id` int(11) NOT NULL, 
    `value` double NOT NULL, 
    PRIMARY KEY (`property_id`,`item_id`), 
    KEY `item_id` (`item_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

cơ sở dữ liệu này có hai mục tiêu: lưu trữ (trong đó có ưu tiên hàng đầu và có thể rất nhanh chóng, tôi muốn thực hiện nhiều chèn (hàng trăm) trong vài giây), lấy dữ liệu (chọn sử dụng item_id và property_id) (Đây là ưu tiên thứ hai, nó có thể chậm hơn nhưng không quá nhiều vì điều này sẽ làm hỏng việc sử dụng DB của tôi).

Hiện tại bảng này lưu trữ 1,6 tỷ mục nhập và số lượng đơn giản có thể mất đến 2 phút ... Chèn không đủ nhanh để có thể sử dụng được.

Tôi đang sử dụng Zend_Db để truy cập dữ liệu của mình và thực sự sẽ vui nếu bạn không đề nghị tôi phát triển bất kỳ phần tử bên PHP nào.

+0

câu hỏi không thực sự liên quan đến php nên tôi đã xóa thẻ này – jigfox

+0

Không vấn đề Jens, bạn đúng là – AsTeR

Trả lời

10

Nếu bạn không thể tìm giải pháp bằng cách sử dụng các hệ thống quản lý cơ sở dữ liệu khác nhau hoặc phân vùng trên một cụm vì một số lý do, vẫn có ba điều chính bạn có thể làm để hoàn toàn cải thiện hiệu suất của bạn (và chúng hoạt động kết hợp với cụm quá tất nhiên):

  • cài đặt động cơ MyISAM lưu trữ
  • Sử dụng "LOAD DATA INFILE filename VÀO TABLE tablename"
  • Tách dữ liệu của bạn trên một số bảng

Vậy đó. Đọc phần còn lại chỉ khi bạn quan tâm đến chi tiết :)

Vẫn đang đọc? OK sau đó, ở đây đi: MyISAM là đá góc, vì nó là động cơ nhanh nhất cho đến nay. Thay vì chèn hàng dữ liệu bằng cách sử dụng câu lệnh SQL thông thường, bạn nên gộp chúng trong một tệp và insert that file theo khoảng thời gian đều đặn (thường xuyên như bạn cần, nhưng ít khi ứng dụng của bạn cho phép là tốt nhất). Bằng cách đó bạn có thể chèn theo thứ tự của một triệu hàng mỗi phút.

Điều tiếp theo sẽ giới hạn bạn là khóa/chỉ mục của bạn. Khi những thứ đó không phù hợp với trí nhớ của bạn (bởi vì chúng chỉ đơn giản là lớn), bạn sẽ gặp phải sự sụt giảm lớn trong cả chèn và truy vấn. Đó là lý do tại sao bạn chia nhỏ dữ liệu trên nhiều bảng, tất cả đều có cùng một lược đồ. Mỗi bảng nên càng lớn càng tốt, mà không làm đầy bộ nhớ của bạn khi nạp một tại một thời điểm. Kích thước chính xác phụ thuộc vào máy tính và chỉ mục của bạn tất nhiên, nhưng phải ở đâu đó giữa 5 và 50 triệu hàng/bảng. Bạn sẽ tìm thấy điều này nếu bạn chỉ đơn giản là đo thời gian thực hiện để chèn một loạt lớn các hàng khác, tìm kiếm thời điểm nó chậm lại đáng kể. Khi bạn biết giới hạn, hãy tạo một bảng mới mỗi khi bảng cuối cùng của bạn đạt đến giới hạn đó.

Hậu quả của giải pháp đa nhiệm là bạn sẽ phải truy vấn tất cả các bảng thay vì chỉ một bảng khi bạn cần một số dữ liệu. chỉ "có một tỷ hoặc nhiều hàng). Rõ ràng là có tối ưu hóa để làm ở đây là tốt. Nếu có điều gì đó cơ bản bạn có thể sử dụng để tách dữ liệu (như ngày, khách hàng hoặc thứ gì đó), bạn có thể chia nó thành các bảng khác nhau bằng cách sử dụng một số mẫu có cấu trúc cho phép bạn biết một số loại dữ liệu nào thậm chí không truy vấn bảng. Sử dụng kiến ​​thức đó để chỉ truy vấn các bảng có thể chứa dữ liệu được yêu cầu, v.v.

Nếu bạn cần điều chỉnh nhiều hơn, hãy đi theo số partitioning, theo đề xuất của Eineki và oedo.

Ngoài ra, vì vậy bạn sẽ biết tất cả điều này không phải là suy đoán hoang dã: Tôi đang thực hiện một số kiểm tra khả năng mở rộng như thế này trên dữ liệu của chúng tôi tại thời điểm này và cách tiếp cận này đang làm điều kỳ diệu đối với chúng tôi. Chúng tôi đang quản lý để chèn hàng chục triệu hàng mỗi ngày và truy vấn mất ~ 100 ms.

+0

Rock'n'roll này dường như là một trong những hoàn chỉnh nhất!Tôi sẽ không cố gắng "tải dữ liệu infile", tôi không có bất kỳ ý chí để viết lại mã ở phía PHP, và điều đó sẽ buộc tôi phải làm như vậy. Tôi sẽ thử những điều partionning và cũng là động cơ thay đổi để MyISAM. – AsTeR

+0

Cập nhật từ 5.0 đến 5.1 mang lại cho tôi một cải tiến hiệu suất đầu tiên. Trước tiên, tôi đã xóa tất cả khóa ngoại và sử dụng 20 phân vùng. Một lựa chọn đơn giản để có được tất cả các thuộc tính (kiểm tra 1): đi từ 0,7 giây đến 0,37. Số lượng tất cả các mục (kiểm tra 2) kéo dài từ hơn một phút đến 11 giây. Sau đó tôi testest 200 phân vùng: thử nghiệm 1: 0,29 s thử nghiệm 2: 14,86 s Cuối cùng tôi đã sử dụng 50 paritions, thay đổi để MyISAM và loại bỏ các chỉ số: thử nghiệm 1: 0,24 s thử nghiệm 2: <0,01 s Cảm ơn tất cả mọi người! – AsTeR

0

Trước hết không sử dụng InnoDb vì bạn dường như không cần tính năng chính của nó trên MyISAM (khóa, giao dịch, v.v.). Vì vậy, sử dụng MyISAM, nó sẽ tạo ra một số khác biệt. Sau đó, nếu điều đó vẫn chưa đủ nhanh, hãy vào một số chỉ mục, nhưng bạn đã thấy sự khác biệt cơ bản.

+1

MyISAM cũng có thể * tồi tệ hơn cả InnoDB thậm chí hoàn toàn là tốc độ. Nếu các bản cập nhật đó xuất hiện đồng thời, khóa cấp bảng của MyISAM có thể có tác động tiêu cực mạnh. – bobince

0

wow, đó là khá một bảng lớn :)

nếu bạn cần lưu trữ để được nhanh chóng, bạn có thể hàng loạt lên chèn của bạn và thêm chúng với một câu lệnh INSERT nhiều đơn. tuy nhiên điều này chắc chắn sẽ yêu cầu thêm mã phía máy khách (php), xin lỗi!

INSERT INTO `table` (`col1`, `col2`) VALUES (1, 2), (3, 4), (5, 6)... 

cũng vô hiệu hóa bất kỳ chỉ mục nào bạn không CẦN làm chỉ mục làm chậm lệnh chèn.

cách khác bạn có thể nhìn vào phân vùng bảng của bạn: linky

+0

Ý tưởng rất hay, nhưng tôi rất thích Zend_Db để kiểm tra điều này. – AsTeR

0

Nhìn vào memcache để xem nơi nó có thể được áp dụng. Ngoài ra nhìn vào phân vùng ngang để giữ kích thước bảng/chỉ mục nhỏ hơn.

+0

Tôi đã sử dụng memcache ... nó không phù hợp với nhu cầu của tôi. Tôi không có gì để lưu vào bộ nhớ cache. Tôi lưu trữ dữ liệu trong thời gian dài và sau đó truy xuất dữ liệu đã được xử lý trước. – AsTeR

0

Đầu tiên: Một bảng có 1,6 tỷ mục nhập có vẻ quá lớn. Tôi làm việc trên một số hệ thống tải khá nặng mà ngay cả các bảng ghi nhật ký theo dõi tất cả các hành động không nhận được điều này lớn qua nhiều năm. Vì vậy, nếu có thể, hãy suy nghĩ, nếu bạn có thể tìm thấy một phương pháp lưu trữ tối ưu hơn. Không thể đưa ra nhiều lời khuyên hơn vì tôi không biết cấu trúc DB của bạn nhưng tôi chắc chắn sẽ có nhiều chỗ để tối ưu hóa. 1,6 tỷ mục chỉ là quá lớn.

Một vài điều về hoạt động:

Nếu bạn không cần phải kiểm tra tính toàn vẹn tham chiếu, đó là khó xảy ra, bạn có thể chuyển sang các công cụ lưu trữ MyISAM. Đó là một chút nhanh hơn nhưng thiếu ckecks toàn vẹn và các giao dịch.

Đối với bất kỳ điều gì khác, cần thêm thông tin.

+0

Giống như một số người khác nói ở đây, tôi đã đọc hơn MyISAM sẽ không làm cho điều này nhanh hơn, nhưng tôi sẽ cố gắng. – AsTeR

+0

Bằng cách này, tôi không sử dụng bất kỳ tính năng innoDB nào – AsTeR

0

Bạn đã xem tùy chọn partitioning bảng chưa?

+0

Không, tôi không có và tôi nghĩ đó có thể là một điểm tối ưu nghiêm trọng. – AsTeR

-1

Một điều quan trọng cần nhớ là cài đặt mặc định của MySQL không được cấu hình cho công việc nặng nhọc như thế này. Đảm bảo rằng bạn có tuned it cho khối lượng công việc của bạn.

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