Tôi đang tìm cách chọn một hàng trong bảng một cách rõ ràng cho một chuỗi. Tôi đã viết một trình thu thập thông tin, hoạt động với khoảng 50 quy trình song song. Mỗi quá trình phải mất một hàng ra khỏi một bảng và xử lý nó.Chỉ chọn một hàng của bảng trên các kết nối song song cao
CREATE TABLE `crawler_queue` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`url` text NOT NULL,
`class_id` tinyint(3) unsigned NOT NULL,
`server_id` tinyint(3) unsigned NOT NULL,
`proc_id` mediumint(8) unsigned NOT NULL,
`prio` tinyint(3) unsigned NOT NULL,
`inserted` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `proc_id` (`proc_id`),
KEY `app_id` (`app_id`),
KEY `crawler` (`class_id`,`prio`,`proc_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
Bây giờ quá trình tôi làm như sau:
- giao dịch bắt đầu DB
- làm một lựa chọn như
SELECT * FROM crawler_queue WHERE class_id=2 AND prio=20 AND proc_id=0 ORDER BY id LIMIT 1 FOR UPDATE
- sau đó cập nhật hàng này với
UPDATE crawler_queue SET server_id=1,proc_id=1376 WHERE id=23892
- cam kết giao dịch
Điều này sẽ giúp không có quá trình nào khác có thể lấy một hàng được xử lý. Làm một giải thích về các chương trình chọn
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE crawler_queue ref proc_id,crawler proc_id 3 const 617609 Using where
Nhưng các quá trình dường như gây ra song song quá cao, bởi vì đôi khi tôi có thể thấy hai loại lỗi/cảnh báo trong nhật ký của tôi (mỗi 5 phút hoặc lâu hơn):
mysqli::query(): (HY000/1205): Lock wait timeout exceeded; try restarting transaction (in /var/www/db.php l
ine 81)
mysqli::query(): (40001/1213): Deadlock found when trying to get lock; try restarting transaction (in /var/www/db.php line 81)
Câu hỏi của tôi là: ai có thể chỉ cho tôi đúng hướng để giảm thiểu các vấn đề về khóa này không? (Trong tình trạng sản xuất, xử lý song song sẽ cao hơn bây giờ 3-4 lần, vì vậy tôi giả định, rằng sẽ có nhiều vấn đề khóa hơn)
EDIT 2012/12/29: Tôi sửa đổi SELECT
sử dụng chỉ số crawler
theo gợi ý USE INDEX(crawler)
. Vấn đề của tôi bây giờ là lockwait timeouts nữa (deadlocks biến mất).
EDIT 2012/12/31: EXPLAIN
với USE INDEX()
thấy bây giờ (không có hàng là cao hơn, vì bảng chứa dữ liệu hơn bây giờ.):
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE crawler_queue ref proc_id,crawler crawler 5 const,const,const 5472426 Using where
Ý tưởng hay, nhưng 'LAST_INSERT_ID()' sẽ trả về giá trị chỉ khi bạn 'INSERT' dữ liệu hoặc' UPDATE' tăng cột autoincrement: ** EDIT ** Tôi sẽ cung cấp http://stackoverflow.com/questions/ 1388025/how-to-get-id-of-the-last-cập nhật-hàng-in-mysql một thử – rabudde
Đối với một số lý do tôi có một giá trị last_insert_id khi tôi thử nghiệm, nhưng nó lừa tôi (nó trông giống như một trong những chính xác, nhưng nó không phải). Tôi tin rằng giải pháp được mô tả trong câu hỏi SO đó là con đường để đi. Tôi cũng sẽ cập nhật câu trả lời của mình. – Xnoise