Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

Oracle:Hiệu suất Thu thập hàng loạt

Trong Oracle, có một máy ảo SQL (VM) và một máy ảo PL / SQL. Khi bạn cần chuyển từ máy ảo này sang máy ảo khác, bạn phải chịu chi phí chuyển ngữ cảnh. Về mặt cá nhân, những thay đổi ngữ cảnh đó tương đối nhanh, nhưng khi bạn đang thực hiện xử lý từng hàng, chúng có thể chiếm một phần đáng kể thời gian mà mã của bạn đang sử dụng. Khi bạn sử dụng liên kết hàng loạt, bạn di chuyển nhiều hàng dữ liệu từ máy ảo này sang máy ảo khác chỉ với một lần dịch chuyển ngữ cảnh, giảm đáng kể số lần dịch chuyển ngữ cảnh, giúp mã của bạn nhanh hơn.

Lấy ví dụ, một con trỏ rõ ràng. Nếu tôi viết một cái gì đó như thế này

DECLARE
  CURSOR c 
      IS SELECT *
           FROM source_table;
  l_rec source_table%rowtype;
BEGIN
  OPEN c;
  LOOP
    FETCH c INTO l_rec;
    EXIT WHEN c%notfound;

    INSERT INTO dest_table( col1, col2, ... , colN )
      VALUES( l_rec.col1, l_rec.col2, ... , l_rec.colN );
  END LOOP;
END;

sau đó mỗi khi tôi thực hiện tìm nạp, tôi

  • Thực hiện chuyển ngữ cảnh từ máy ảo PL / SQL sang máy ảo SQL
  • Yêu cầu máy ảo SQL thực thi con trỏ để tạo hàng dữ liệu tiếp theo
  • Thực hiện chuyển ngữ cảnh khác từ SQL VM trở lại PL / SQL VM để trả về một hàng dữ liệu duy nhất của tôi

Và mỗi khi tôi chèn một hàng, tôi đang làm điều tương tự. Tôi phải chịu chi phí chuyển ngữ cảnh để chuyển một hàng dữ liệu từ PL / SQL VM sang SQL VM, yêu cầu SQL thực thi INSERT và sau đó phải chịu chi phí của việc chuyển ngữ cảnh khác trở lại PL / SQL.

Nếu source_table có 1 triệu hàng, đó là 4 triệu thay đổi ngữ cảnh có thể sẽ chiếm một phần hợp lý trong thời gian đã trôi qua của mã của tôi. Mặt khác, nếu tôi thực hiện BULK COLLECT với LIMIT là 100, tôi có thể loại bỏ 99% sự thay đổi ngữ cảnh của mình bằng cách truy xuất 100 hàng dữ liệu từ SQL VM vào một bộ sưu tập trong PL / SQL mỗi khi tôi phải chịu chi phí thay đổi ngữ cảnh và chèn 100 hàng vào bảng đích mỗi khi tôi phải chịu sự thay đổi bối cảnh ở đó.

Nếu có thể viết lại mã của tôi để sử dụng các hoạt động hàng loạt

DECLARE
  CURSOR c 
      IS SELECT *
           FROM source_table;
  TYPE  nt_type IS TABLE OF source_table%rowtype;
  l_arr nt_type;
BEGIN
  OPEN c;
  LOOP
    FETCH c BULK COLLECT INTO l_arr LIMIT 100;
    EXIT WHEN l_arr.count = 0;

    FORALL i IN 1 .. l_arr.count
      INSERT INTO dest_table( col1, col2, ... , colN )
        VALUES( l_arr(i).col1, l_arr(i).col2, ... , l_arr(i).colN );
  END LOOP;
END;

Bây giờ, mỗi khi tôi thực hiện tìm nạp, tôi lấy 100 hàng dữ liệu vào bộ sưu tập của mình với một bộ thay đổi ngữ cảnh. Và mỗi khi tôi thực hiện FORALL chèn, tôi đang chèn 100 hàng với một bộ thay đổi ngữ cảnh. Nếu source_table có 1 triệu hàng, điều này có nghĩa là tôi đã đi từ 4 triệu lượt thay đổi ngữ cảnh đến 40.000 lượt thay đổi ngữ cảnh. Nếu thay đổi ngữ cảnh chiếm 20% thời gian đã trôi qua của mã của tôi, thì tôi đã loại bỏ 19,8% thời gian đã trôi qua.

Bạn có thể tăng kích thước của LIMIT để giảm hơn nữa số lần thay đổi ngữ cảnh nhưng bạn nhanh chóng đạt được quy luật lợi nhuận giảm dần. Nếu bạn đã sử dụng LIMIT 1000 thay vì 100, bạn sẽ loại bỏ 99,9% sự thay đổi ngữ cảnh thay vì 99%. Tuy nhiên, điều đó có nghĩa là bộ sưu tập của bạn đang sử dụng bộ nhớ PGA gấp 10 lần. Và nó sẽ chỉ loại bỏ thêm 0,18% thời gian đã trôi qua trong ví dụ giả định của chúng tôi. Bạn rất nhanh chóng đạt đến điểm mà bộ nhớ bổ sung bạn đang sử dụng thêm nhiều thời gian hơn bạn tiết kiệm bằng cách loại bỏ các dịch chuyển ngữ cảnh bổ sung. Nói chung, LIMIT khoảng từ 100 đến 1000 có thể là điểm hấp dẫn.

Tất nhiên, trong ví dụ này, vẫn sẽ hiệu quả hơn nếu loại bỏ tất cả các thay đổi ngữ cảnh và thực hiện mọi thứ trong một câu lệnh SQL duy nhất

INSERT INTO dest_table( col1, col2, ... , colN )
  SELECT col1, col2, ... , colN
    FROM source_table;

Sẽ chỉ có ý nghĩa khi sử dụng PL / SQL ngay từ đầu nếu bạn đang thực hiện một số thao tác đối với dữ liệu từ bảng nguồn mà bạn không thể triển khai hợp lý trong SQL.

Ngoài ra, tôi đã cố ý sử dụng một con trỏ rõ ràng trong ví dụ của mình. Nếu bạn đang sử dụng con trỏ ngầm, trong các phiên bản gần đây của Oracle, bạn sẽ nhận được lợi ích của BULK COLLECT với LIMIT của 100 ngầm định. Có một câu hỏi StackOverflow khác thảo luận về lợi ích hiệu suất tương đối của con trỏ ẩn và rõ ràng với các hoạt động hàng loạt, đi sâu hơn vào các nếp nhăn cụ thể đó.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Xóa các hàng trùng lặp trong bảng

  2. XUẤT NHƯ THỐNG KÊ CHÈN:Nhưng trong SQL Plus, dòng ghi đè lên 2500 ký tự!

  3. Số ngày thứ sáu giữa hai ngày

  4. Tự động tăng dần cho Oracle

  5. Cài đặt NLS_LANG cho trình điều khiển mỏng JDBC?