2012-02-02 43 views
9

Gần đây tôi đã chuyển các bảng dự án của tôi sang InnoDB (nghĩ rằng các mối quan hệ sẽ là một điều tốt đẹp để có). Tôi đang sử dụng một tập lệnh PHP để lập chỉ mục khoảng 500 sản phẩm cùng một lúc.InnoDB chèn rất chậm và chậm lại

Một từ/id gắn bảng lưu trữ:

CREATE TABLE `windex` (
`word` varchar(64) NOT NULL, 
`wid` int(10) unsigned NOT NULL AUTO_INCREMENT, 
`count` int(11) unsigned NOT NULL DEFAULT '1', 
PRIMARY KEY (`wid`), 
UNIQUE KEY `word` (`word`) 
) ENGINE=InnoDB AUTO_INCREMENT=324551 DEFAULT CHARSET=latin1 

Một bảng các cửa hàng sản phẩm id/từ hiệp hội id:

CREATE TABLE `indx_0` (
`wid` int(7) unsigned NOT NULL, 
`pid` int(7) unsigned NOT NULL, 
UNIQUE KEY `wid` (`wid`,`pid`), 
KEY `pid` (`pid`), 
CONSTRAINT `indx_0_ibfk_1` FOREIGN KEY (`wid`) REFERENCES `windex` (`wid`) ON DELETE CASCADE ON UPDATE CASCADE, 
CONSTRAINT `indx_0_ibfk_2` FOREIGN KEY (`pid`) REFERENCES `product` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

Các kịch bản đã được thử nghiệm sử dụng MyISAM và nó chỉ số sản phẩm tương đối nhanh (nhiều , nhanh hơn nhiều so với InnoDB). Lần đầu tiên chạy trong InnoDB nó đã được ridiculously chậm nhưng sau khi làm tổ nhiều giá trị với nhau tôi đã kết thúc tăng tốc nó lên bởi rất nhiều (nhưng không đủ).

Tôi cho rằng innodb sẽ nhanh hơn nhiều đối với loại điều này vì khóa rowlevel nhưng đó không phải là trường hợp.

tôi xây dựng một truy vấn mà trông giống như sau:

SELECT 
title,keywords,upc,... 
FROM product 
WHERE indexed = 0 
LIMIT 500 

tôi tạo ra một vòng lặp và điền một mảng với tất cả những từ mà cần phải được bổ sung vào Windex và tất cả các cặp từ id/sản phẩm id cần được thêm vào indx_0.

Bởi vì innodb tiếp tục tăng giá trị tăng tự động của tôi bất cứ khi nào tôi thực hiện "REPLACE INTO" hoặc "INSERT IGNORE INTO" không thành công do giá trị trùng lặp, tôi cần đảm bảo giá trị tôi thêm chưa tồn tại. Để làm điều đó đầu tiên tôi chọn tất cả các giá trị mà tồn tại sử dụng một truy vấn như ví dụ:

SELECT wid,word 
FROM windex 
WHERE 
word = "someword1" or word = "someword2" or word = "someword3" ... ... 

Sau đó, tôi lọc ra các mảng của tôi chống lại những kết quả mà tồn tại vì vậy tất cả các từ mới tôi thêm là 100% mới.

Điều này mất khoảng 20% ​​thời gian thực hiện tổng thể. 80% còn lại đi vào việc thêm các giá trị của cặp vào indx_0, trong đó có nhiều giá trị hơn.

Dưới đây là ví dụ về những gì tôi nhận được.

0.4806 giây để chọn sản phẩm. (Tổng số 0,4807 giây).
0,0319 giây để thu thập 500 mục. (Tổng số 0,5126 giây).
5.2396 giây để chọn giá trị windex để so sánh. (5.7836 giây).
1.8986 giây để cập nhật số lượng. (Tổng cộng 7.6822 giây).
0,0641 giây để thêm 832 bản ghi windex. (Tổng số 7,7464 giây).
17,2725 giây để thêm chỉ mục của 3435 cặp pid/wid. (Tổng số 25.7752 giây).
Hoạt động mất 26,07 giây để lập chỉ mục 500 sản phẩm.

Các cặp 3435 đang được tất cả được thực hiện trong một truy vấn như:

INSERT INTO indx_0(pid,wid) 
VALUES (1,4),(3,9),(9,2)... ... ... 

Tại sao là InnoDB nên chậm hơn nhiều so với MyISAM trong trường hợp của tôi?

+0

Ý tưởng chỉ mục từ để tạo một số chức năng tìm kiếm? Nếu đó là trường hợp, đã được thực hiện điều đó, hãy kiểm tra một công cụ tìm kiếm thực sự như solr hoặc mysql tìm kiếm fulltext ví dụ. Không thể làm tốt hơn các tác vụ cụ thể đó. –

Trả lời

13

InnoDB cung cấp cấu trúc khóa phức tạp hơn MyIsam (FOREIGN KEYS) và các khóa tạo lại thực sự chậm trong InnoDB.Bạn nên gửi kèm tất cả các câu lệnh update/insert vào một giao dịch (thực sự là khá nhanh trong InnoDB, một khi tôi có khoảng 300 000 truy vấn chèn trên bảng InnoDb với 2 chỉ mục và mất khoảng 30 phút, một khi tôi đính kèm mỗi 10 000 chèn vào BEGIN TRANSACTIONCOMMIT mất ít hơn 2 phút).

Tôi khuyên bạn nên sử dụng:

BEGIN TRANSACTION; 
SELECT ... FROM products; 
UPDATE ...; 
INSERT INTO ...; 
INSERT INTO ...; 
INSERT INTO ...; 
COMMIT; 

Điều này sẽ gây InnoDB để làm mới các chỉ số chỉ một lần không vài trăm lần.

Hãy cho tôi biết nếu nó làm việc

+0

Nó sẽ mang lại một số cải tiến chắc chắn tôi tin. Tôi có một vấn đề tương tự Vyktor. Có vẻ như điều này sẽ làm việc. Thanks -Uday – Uday

+2

Tôi đã gặp sự cố trong con trỏ mà lỗi này đã sửa (từ 90 giây đến 0,9!) Từ từ tôi đang học những gì được yêu cầu của InnoDB –

+0

@Vyktor, Về * "Tôi đã đính kèm mỗi 10 000 lần chèn vào 'BEGIN TRANSACTION' và 'COMMIT' mất ít hơn 2 phút" *, Tại sao bạn chia thành 10 nghìn lô? Tại sao không gửi kèm ** tất cả các câu lệnh ** trong một giao dịch duy nhất? – Pacerier

4

Tôi đã có một vấn đề tương tự và có vẻ như InnoDB có bằng innodb_flush_log_at_trx_commit mặc định kích hoạt mà xả mỗi chèn/cập nhật truy vấn trên log file hdd của bạn. Tốc độ ghi của đĩa cứng của bạn là một nút cổ chai cho quá trình này.

Vì vậy, cố gắng sửa đổi tập tin cấu hình mysql của bạn

`innodb_flush_log_at_trx_commit = 0` 

dịch vụ Khởi động lại mysql.

Tôi đã trải nghiệm về tốc độ x100 trên chèn.

+1

Xin lưu ý rằng an toàn giao dịch bị mất khi áp dụng tùy chọn này ... Nếu bạn mất điện sau khi thông báo cho khách hàng, nhưng trước khi nó thực sự được ghi vào đĩa có nghĩa là nó sẽ bị mất vĩnh viễn. – Cine