Câu trả lời:
https://dev.mysql.com/doc/refman/8.0/en/insert-optimization.html
Thời gian cần thiết để chèn một hàng được xác định bởi các yếu tố sau, trong đó các con số biểu thị tỷ lệ gần đúng:
- Kết nối: (3)
- Gửi truy vấn đến máy chủ: (2)
- Truy vấn phân tích cú pháp: (2)
- Chèn hàng: (kích thước 1 × của hàng)
- Chèn chỉ mục: (1 × số chỉ mục)
- Kết thúc: (1)
Từ điều này, rõ ràng là việc gửi một câu lệnh lớn sẽ giúp bạn tiết kiệm được 7 chi phí cho mỗi câu lệnh chèn, trong khi đọc thêm văn bản cũng cho biết:
Nếu bạn đang chèn nhiều hàng từ cùng một máy khách cùng một lúc, hãy sử dụng các câu lệnh INSERT với nhiều danh sách GIÁ TRỊ để chèn nhiều hàng cùng một lúc. Điều này nhanh hơn đáng kể (trong nhiều trường hợp nhanh hơn nhiều lần) so với sử dụng các câu lệnh INSERT một hàng riêng biệt.
Tôi biết tôi đã trả lời câu hỏi này gần hai năm rưỡi sau khi được hỏi, nhưng tôi chỉ muốn cung cấp một số dữ liệu cứng từ một dự án mà tôi đang làm việc ngay bây giờ cho thấy rằng thực sự thực hiện nhiều khối GIÁ TRỊ cho mỗi lần chèn là NHIỀU nhanh hơn các câu lệnh INSERT khối đơn tuần tự.
Mã tôi đã viết cho điểm chuẩn này trong C # sử dụng ODBC để đọc dữ liệu vào bộ nhớ từ nguồn dữ liệu MSSQL (~ 19.000 hàng, tất cả đều được đọc trước khi bắt đầu viết) và trình kết nối MySql .NET (Mysql.Data. *) XÁC NHẬN dữ liệu từ bộ nhớ vào bảng trên máy chủ MySQL thông qua các câu lệnh được chuẩn bị. Nó được viết theo cách cho phép tôi điều chỉnh linh hoạt số lượng khối GIÁ TRỊ trên mỗi INSERT đã chuẩn bị (nghĩa là chèn n hàng tại một thời điểm, nơi tôi có thể điều chỉnh giá trị của n trước khi chạy.) Tôi cũng đã chạy thử nghiệm nhiều lần cho mỗi n.
Thực hiện các khối GIÁ TRỊ duy nhất (ví dụ: 1 hàng tại một thời điểm) mất 5,7 - 5,9 giây để chạy. Các giá trị khác như sau:
2 hàng cùng một lúc: 3,5 - 3,5 giây
5 hàng cùng một lúc: 2,2 - 2,2 giây
10 hàng một lần: 1,7 - 1,7 giây
50 hàng tại một thời điểm: 1,17 - 1,18 giây
100 hàng tại một thời điểm: 1,1 - 1,4 giây
500 hàng cùng một lúc: 1,1 - 1,2 giây
1000 hàng tại một thời điểm: 1,17 - 1,17 giây
Vì vậy, có, ngay cả việc kết hợp 2 hoặc 3 ghi lại với nhau cũng mang lại sự cải thiện đáng kể về tốc độ (thời gian chạy bị cắt bởi hệ số n), cho đến khi bạn đến một nơi nào đó giữa n = 5 và n = 10, tại đó điểm cải thiện giảm xuống rõ rệt, và ở đâu đó trong phạm vi n = 10 đến n = 50, sự cải thiện trở nên không đáng kể.
Hy vọng điều đó giúp mọi người quyết định (a) có nên sử dụng ý tưởng đa phương thức hay không và (b) có bao nhiêu khối GIÁ TRỊ để tạo cho mỗi câu lệnh (giả sử bạn muốn làm việc với dữ liệu có thể đủ lớn để đẩy truy vấn vượt quá kích thước truy vấn tối đa đối với MySQL, mà tôi tin là 16 MB theo mặc định ở nhiều nơi, có thể lớn hơn hoặc nhỏ hơn tùy thuộc vào giá trị của max_allowed_packet được đặt trên máy chủ.)
Một yếu tố chính sẽ là liệu bạn có đang sử dụng một công cụ giao dịch hay không và liệu bạn có tự động truy cập hay không.
Autocommit được bật theo mặc định và bạn có thể muốn để nó trên; do đó, mỗi lần chèn mà bạn thực hiện giao dịch riêng. Điều này có nghĩa là nếu bạn thực hiện một lần chèn mỗi hàng, bạn sẽ thực hiện giao dịch cho mỗi hàng.
Giả sử một luồng duy nhất, điều đó có nghĩa là máy chủ cần đồng bộ hóa một số dữ liệu vào đĩa cho MERYI ROW. Nó cần đợi dữ liệu đến một vị trí lưu trữ liên tục (hy vọng ram được hỗ trợ bằng pin trong bộ điều khiển RAID của bạn). Điều này vốn đã khá chậm và có lẽ sẽ trở thành yếu tố hạn chế trong những trường hợp này.
Tất nhiên tôi giả sử rằng bạn đang sử dụng một công cụ giao dịch (thường là innodb) VÀ rằng bạn đã không điều chỉnh các cài đặt để giảm độ bền.
Tôi cũng giả sử rằng bạn đang sử dụng một luồng duy nhất để thực hiện các thao tác chèn này. Sử dụng nhiều luồng làm vướng víu một chút vì một số phiên bản của MySQL có cam kết nhóm hoạt động trong innodb - điều này có nghĩa là nhiều luồng thực hiện cam kết của riêng chúng có thể chia sẻ một lần ghi vào nhật ký giao dịch, điều này tốt vì điều đó có nghĩa là ít đồng bộ hóa hơn với lưu trữ liên tục .
Mặt khác, kết quả cuối cùng là, bạn THỰC SỰ MUỐN SỬ DỤNG các phần chèn nhiều hàng.
Có một giới hạn mà nó phản tác dụng, nhưng trong hầu hết các trường hợp, nó có ít nhất 10.000 hàng. Vì vậy, nếu bạn bó chúng lên tới 1.000 hàng, có lẽ bạn an toàn.
Nếu bạn đang sử dụng MyISAM, sẽ có vô số thứ khác, nhưng tôi sẽ không làm bạn chán với những thứ đó. Sự thanh bình.
Nói chung, số lượng cuộc gọi đến cơ sở dữ liệu càng ít càng tốt (nghĩa là nhanh hơn, hiệu quả hơn), vì vậy hãy thử mã hóa các phần chèn theo cách sao cho tối thiểu hóa truy cập cơ sở dữ liệu. Hãy nhớ rằng, trừ khi bạn sử dụng nhóm kết nối, mỗi lần truy cập cơ sở dữ liệu phải tạo kết nối, thực thi sql và sau đó phá bỏ kết nối. Một chút chi phí!
Bạn có thể muốn :
Tùy thuộc vào quy mô như thế nào máy chủ của bạn (nó dứt khoát ok với PostgreSQl
, Oracle
và MSSQL
), làm điều trên với nhiều chủ đề và nhiều kết nối.
Nói chung, nhiều lần chèn sẽ chậm hơn do chi phí kết nối. Thực hiện nhiều lần chèn cùng một lúc sẽ giảm chi phí cho mỗi lần chèn.
Tùy thuộc vào ngôn ngữ bạn đang sử dụng, bạn có thể tạo một lô trong ngôn ngữ lập trình / kịch bản của mình trước khi đi tới db và thêm từng ngôn ngữ vào lô. Sau đó, bạn sẽ có thể thực hiện một lô lớn bằng một thao tác kết nối. Đây là một ví dụ trong Java.
Thật nực cười khi Mysql và MariaDB xấu được tối ưu hóa như thế nào khi chèn. Tôi đã thử nghiệm mysql 5.7 và mariadb 10.3, không có sự khác biệt thực sự trên những cái đó.
Tôi đã thử nghiệm điều này trên máy chủ với các đĩa NVME, 70.000 IOPS, thông lượng seq 1.1 GB / giây và đó là khả năng song công hoàn toàn (đọc và ghi).
Các máy chủ là một máy chủ hiệu suất cao là tốt.
Đã cho nó 20 GB ram.
Cơ sở dữ liệu hoàn toàn trống rỗng.
Tốc độ tôi nhận được là 5000 lần chèn mỗi giây khi thực hiện chèn nhiều hàng (đã thử với khối dữ liệu 1MB lên đến 10 MB)
Bây giờ đầu mối:
Nếu tôi thêm một chủ đề khác và chèn vào các bảng CÙNG tôi đột nhiên có 2x5000 / giây. Thêm một chủ đề và tôi có tổng số 15000 / giây
Xem xét điều này: Khi thực hiện MỘT luồng chèn, điều đó có nghĩa là bạn có thể ghi tuần tự vào đĩa (ngoại trừ các chỉ mục). Khi sử dụng các chủ đề, bạn thực sự làm giảm hiệu suất có thể bởi vì bây giờ nó cần phải thực hiện nhiều truy cập ngẫu nhiên hơn. Nhưng kiểm tra thực tế cho thấy mysql được tối ưu hóa rất tệ đến mức các chủ đề giúp ích rất nhiều.
Hiệu suất thực sự có thể với một máy chủ như vậy có thể là hàng triệu mỗi giây, CPU không hoạt động, đĩa không hoạt động.
Lý do khá rõ ràng là mariadb cũng giống như mysql có sự chậm trễ nội bộ.
id
, parent_id
) GIÁ TRỊ (1, NULL). Một trong những bộ giá trị tiếp theo liên kết đến hàng đó. Nếu bạn chia thành các phần và tập hợp đó được chuyển sang phần khác, nó có thể được xử lý trước phần đầu tiên, làm hỏng toàn bộ quá trình. Bất cứ ý tưởng làm thế nào để đối phó với điều đó?
nhiều chèn nhanh hơn nhưng nó có thredshould. một thrik khác đang vô hiệu hóa các ràng buộc kiểm tra temprorary làm cho việc chèn nhanh hơn nhiều. Nó không quan trọng bàn của bạn có hay không. Ví dụ: kiểm tra vô hiệu hóa khóa ngoại và tận hưởng tốc độ:
SET FOREIGN_KEY_CHECKS=0;
bạn nên bật lại sau khi chèn bằng cách:
SET FOREIGN_KEY_CHECKS=1;
Đây là cách phổ biến để chèn dữ liệu lớn. tính tích hợp dữ liệu có thể bị phá vỡ vì vậy bạn nên quan tâm đến điều đó trước khi vô hiệu hóa kiểm tra khóa ngoại.