Bất kỳ INSERT ... SELECT ...
truy vấn có có được khóa CHIA SẺ
không trên các hàng mà nó đọc từ bảng nguồn trong SELECT. Nhưng bằng cách xử lý các phần hàng nhỏ hơn, khóa không kéo dài quá lâu.
Truy vấn với LIMIT ... OFFSET
sẽ ngày càng chậm hơn khi bạn chuyển qua bảng nguồn. Với 10.000 hàng mỗi đoạn, bạn cần chạy truy vấn đó 10.000 lần, mỗi truy vấn phải bắt đầu lại và quét qua bảng để đạt được OFFSET mới.
Bất kể bạn làm gì, việc sao chép 100 triệu hàng sẽ mất một khoảng thời gian. Nó đang làm rất nhiều việc.
Tôi sẽ sử dụng pt-archiver , một công cụ miễn phí được thiết kế cho mục đích này. Nó xử lý các hàng trong "khối" (hoặc tập hợp con). Nó sẽ tự động điều chỉnh kích thước của các phần để mỗi phần mất 0,5 giây.
Sự khác biệt lớn nhất giữa phương pháp của bạn và pt-archiver là pt-archiver không sử dụng LIMIT ... OFFSET
, nó đi dọc theo chỉ mục khóa chính, chọn các phần hàng theo giá trị thay vì theo vị trí. Vì vậy, mọi đoạn được đọc hiệu quả hơn.
Nhận xét lại của bạn:
Tôi hy vọng rằng việc làm cho kích thước lô nhỏ hơn - và tăng số lần lặp lại - sẽ làm cho vấn đề về hiệu suất tồi tệ hơn , không tốt hơn.
Lý do là khi bạn sử dụng LIMIT
với OFFSET
, mọi truy vấn phải bắt đầu lại ở đầu bảng và đếm các hàng lên đến OFFSET
giá trị. Điều này ngày càng lâu hơn khi bạn lặp lại qua bảng.
Chạy 20.000 truy vấn đắt tiền bằng OFFSET
sẽ mất nhiều thời gian hơn so với việc chạy 10.000 truy vấn tương tự. Phần đắt nhất sẽ không phải là đọc 5.000 hoặc 10.000 hàng, hoặc chèn chúng vào bảng đích. Phần đắt tiền sẽ được bỏ qua ~ 50.000.000 hàng, lặp đi lặp lại.
Thay vào đó, bạn nên lặp lại bảng theo giá trị không phải bằng hiệu số.
INSERT IGNORE INTO Table2(id, field2, field3)
SELECT f1, f2, f3
FROM Table1
WHERE id BETWEEN rowOffset AND rowOffset+limitSize;
Trước vòng lặp, hãy truy vấn MIN (id) và MAX (id) và bắt đầu rowOffset
ở giá trị nhỏ nhất và lặp lại đến giá trị lớn nhất.
Đây là cách pt-archiver hoạt động.