PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Tôi khuyên bạn nên đọc bản ghi của báo cáo đầu năm 2016 của Vladimir Sitnikov “PostgreSQL và JDBC đang vắt hết nước trái cây”

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Chào buổi chiều Tên tôi là Vladimir Sitnikov. Tôi đã làm việc cho NetCracker được 10 năm. Và tôi chủ yếu tập trung vào năng suất. Mọi thứ liên quan đến Java, mọi thứ liên quan đến SQL đều là thứ tôi yêu thích.

Và hôm nay tôi sẽ nói về những gì chúng tôi gặp phải trong công ty khi bắt đầu sử dụng PostgreSQL làm máy chủ cơ sở dữ liệu. Và chúng tôi chủ yếu làm việc với Java. Nhưng điều tôi sắp nói với bạn hôm nay không chỉ là về Java. Như thực tế đã cho thấy, điều này cũng xảy ra ở các ngôn ngữ khác.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Chúng ta sẽ nói chuyện:

  • về việc lấy mẫu dữ liệu.
  • Về việc lưu dữ liệu.
  • Và cả về hiệu suất.
  • Và về những chiếc cào dưới nước được chôn ở đó.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Hãy bắt đầu với một câu hỏi đơn giản. Chúng tôi chọn một hàng từ bảng dựa trên khóa chính.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Cơ sở dữ liệu được đặt trên cùng một máy chủ. Và tất cả quá trình canh tác này mất 20 mili giây.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

20 mili giây này là rất nhiều. Nếu bạn có 100 yêu cầu như vậy thì bạn sẽ phải tốn thời gian mỗi giây để duyệt qua những yêu cầu này, tức là chúng ta đang lãng phí thời gian.

Chúng tôi không muốn làm điều này và xem xét những gì cơ sở cung cấp cho chúng tôi cho việc này. Cơ sở dữ liệu cung cấp cho chúng ta hai tùy chọn để thực hiện truy vấn.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Tùy chọn đầu tiên là một yêu cầu đơn giản. Điều gì tốt về nó? Thực tế là chúng tôi lấy nó và gửi nó, và không có gì hơn.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

https://github.com/pgjdbc/pgjdbc/pull/478

Cơ sở dữ liệu cũng có một truy vấn nâng cao, phức tạp hơn nhưng có nhiều chức năng hơn. Bạn có thể gửi riêng yêu cầu phân tích cú pháp, thực thi, liên kết biến, v.v.

Truy vấn siêu mở rộng là nội dung mà chúng tôi sẽ không đề cập trong báo cáo hiện tại. Có lẽ chúng tôi muốn thứ gì đó từ cơ sở dữ liệu và có một danh sách mong muốn đã được hình thành dưới một hình thức nào đó, tức là đây là thứ chúng tôi muốn, nhưng điều đó là không thể bây giờ và trong năm tới. Vì vậy, chúng tôi chỉ ghi lại nó và chúng tôi sẽ đi khắp nơi để lay động những người chính.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Và những gì chúng ta có thể làm là truy vấn đơn giản và truy vấn mở rộng.

Mỗi cách tiếp cận có gì đặc biệt?

Một truy vấn đơn giản sẽ phù hợp để thực hiện một lần. Làm xong rồi quên luôn. Và vấn đề là nó không hỗ trợ định dạng dữ liệu nhị phân, tức là nó không phù hợp với một số hệ thống hiệu suất cao.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Truy vấn mở rộng - cho phép bạn tiết kiệm thời gian phân tích cú pháp. Đây là những gì chúng tôi đã làm và bắt đầu sử dụng. Điều này thực sự đã giúp chúng tôi rất nhiều. Không chỉ có tiết kiệm khi phân tích cú pháp. Có những khoản tiết kiệm khi truyền dữ liệu. Truyền dữ liệu ở định dạng nhị phân hiệu quả hơn nhiều.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Hãy chuyển sang thực hành. Đây là giao diện của một ứng dụng điển hình. Nó có thể là Java, v.v.

Chúng tôi đã tạo tuyên bố. Đã thực hiện lệnh. Tạo gần. Sai lầm ở đây là ở đâu? Vấn đề là gì? Không có gì. Đây là những gì nó nói trong tất cả các cuốn sách. Đây là cách nó nên được viết. Nếu bạn muốn hiệu suất tối đa, hãy viết như thế này.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Nhưng thực tế đã chỉ ra rằng điều này không hiệu quả. Tại sao? Bởi vì chúng tôi có một phương pháp "đóng". Và khi chúng tôi làm điều này, từ quan điểm cơ sở dữ liệu, nó giống như một người hút thuốc làm việc với cơ sở dữ liệu. Chúng tôi đã nói "PARSE EXECUTE DEALOCATE".

Tại sao tất cả việc tạo ra và dỡ bỏ các báo cáo bổ sung này? Không ai cần chúng. Nhưng điều thường xảy ra trong preparedStatements là khi chúng ta đóng chúng, chúng sẽ đóng mọi thứ trên cơ sở dữ liệu. Đây không phải là điều chúng tôi muốn.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Chúng tôi muốn, giống như những người khỏe mạnh, làm việc với cơ sở. Chúng tôi đã lấy và chuẩn bị tuyên bố của mình một lần, sau đó chúng tôi thực hiện nó nhiều lần. Trên thực tế, đã nhiều lần - đây là lần duy nhất trong toàn bộ vòng đời của ứng dụng - chúng đã được phân tích cú pháp. Và chúng tôi sử dụng cùng một id câu lệnh trên các REST khác nhau. Đây là mục tiêu của chúng tôi.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Làm thế nào chúng ta có thể đạt được điều này?

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Rất đơn giản - không cần phải đóng câu lệnh. Chúng tôi viết nó như thế này: “chuẩn bị” “thực thi”.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Nếu chúng tôi khởi chạy một thứ như thế này, thì rõ ràng thứ gì đó sẽ tràn ra đâu đó. Nếu nó không rõ ràng, bạn có thể thử nó. Hãy viết một điểm chuẩn sử dụng phương pháp đơn giản này. Tạo một tuyên bố. Chúng tôi khởi chạy nó trên một số phiên bản trình điều khiển và nhận thấy rằng nó gặp sự cố khá nhanh do mất toàn bộ bộ nhớ mà nó có.

Rõ ràng là những lỗi như vậy có thể dễ dàng sửa chữa. Tôi sẽ không nói về họ. Nhưng tôi sẽ nói rằng phiên bản mới hoạt động nhanh hơn nhiều. Phương pháp này thật ngu ngốc, nhưng vẫn vậy.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Làm thế nào để làm việc chính xác? Chúng ta cần làm gì cho việc này?

Trong thực tế, các ứng dụng luôn đóng các câu lệnh. Trong tất cả các cuốn sách đều nói hãy đóng nó lại, nếu không bộ nhớ sẽ bị rò rỉ.

Và PostgreSQL không biết cách lưu trữ các truy vấn. Điều cần thiết là mỗi phiên tạo bộ đệm này cho chính nó.

Và chúng tôi cũng không muốn lãng phí thời gian vào việc phân tích cú pháp.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Và như thường lệ, chúng ta có hai lựa chọn.

Tùy chọn đầu tiên là chúng tôi lấy nó và nói rằng hãy gói mọi thứ trong PGSQL. Có một bộ đệm ở đó. Nó lưu trữ mọi thứ. Nó sẽ trở nên tuyệt vời. Chúng tôi đã thấy điều này. Chúng tôi có 100500 yêu cầu. Không hoạt động. Chúng tôi không đồng ý biến các yêu cầu thành thủ tục theo cách thủ công. Không không.

Chúng tôi có lựa chọn thứ hai - lấy nó và tự cắt nó. Chúng tôi mở các nguồn và bắt đầu cắt. Chúng tôi đã thấy và đã thấy. Hóa ra nó không quá khó để làm.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

https://github.com/pgjdbc/pgjdbc/pull/319

Điều này xuất hiện vào tháng 2015 năm XNUMX. Bây giờ có một phiên bản hiện đại hơn. Và mọi thứ đều tuyệt vời. Nó hoạt động tốt đến mức chúng tôi không thay đổi bất cứ điều gì trong ứng dụng. Và chúng tôi thậm chí đã ngừng suy nghĩ theo hướng PGSQL, tức là điều này là khá đủ để chúng tôi giảm tất cả chi phí chung xuống gần như bằng không.

Theo đó, các câu lệnh do Server chuẩn bị sẽ được kích hoạt vào lần thực thi thứ 5 nhằm tránh lãng phí bộ nhớ trong cơ sở dữ liệu theo mỗi yêu cầu một lần.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Bạn có thể hỏi – những con số ở đâu? Bạn đang nhận được gì? Và ở đây tôi sẽ không đưa ra con số, vì mỗi yêu cầu đều có yêu cầu riêng.

Các truy vấn của chúng tôi đến mức chúng tôi đã dành khoảng 20 mili giây để phân tích cú pháp các truy vấn OLTP. Có 0,5 mili giây để thực thi, 20 mili giây để phân tích cú pháp. Yêu cầu – 10 KiB văn bản, 170 dòng kế hoạch. Đây là một yêu cầu OLTP. Nó yêu cầu 1, 5, 10 dòng, đôi khi nhiều hơn.

Nhưng chúng tôi không muốn lãng phí 20 mili giây chút nào. Chúng tôi đã giảm nó xuống 0. Mọi thứ đều tuyệt vời.

Bạn có thể lấy đi những gì từ đây? Nếu bạn có Java, thì bạn hãy lấy phiên bản trình điều khiển hiện đại và tận hưởng.

Nếu bạn nói một ngôn ngữ khác, hãy nghĩ xem - có lẽ bạn cũng cần ngôn ngữ này? Bởi vì từ quan điểm của ngôn ngữ cuối cùng, chẳng hạn, nếu PL 8 hoặc bạn có LibPQ, thì bạn không thấy rõ rằng mình đang dành thời gian không để thực thi, phân tích cú pháp và điều này đáng để kiểm tra. Làm sao? Mọi thứ đều miễn phí.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Ngoại trừ việc có sai sót và một số đặc thù. Và chúng ta sẽ nói về họ ngay bây giờ. Phần lớn sẽ là về khảo cổ học công nghiệp, về những gì chúng tôi tìm thấy, những gì chúng tôi đã gặp.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Nếu yêu cầu được tạo động. Nó xảy ra. Ai đó dán các chuỗi lại với nhau, tạo ra một truy vấn SQL.

Tại sao anh ấy lại xấu? Thật tệ vì mỗi lần chúng ta lại nhận được một chuỗi khác nhau.

Và mã băm của chuỗi khác này cần được đọc lại. Đây thực sự là một nhiệm vụ của CPU - việc tìm kiếm một văn bản yêu cầu dài ngay cả trong hàm băm hiện có không phải là điều dễ dàng. Do đó, kết luận rất đơn giản - không tạo ra yêu cầu. Lưu trữ chúng trong một biến. Và hãy vui mừng.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Vấn đề tiếp theo. Các loại dữ liệu rất quan trọng. Có những ORM nói rằng không quan trọng có loại NULL nào, hãy có một loại nào đó. Nếu Int thì chúng ta nói setInt. Và nếu NULL thì hãy để nó luôn là VARCHAR. Và cuối cùng nó tạo ra sự khác biệt gì khi có NULL? Bản thân cơ sở dữ liệu sẽ hiểu mọi thứ. Và hình ảnh này không hoạt động.

Trong thực tế, cơ sở dữ liệu không quan tâm chút nào. Nếu lần đầu tiên bạn nói rằng đây là một số và lần thứ hai bạn nói rằng đó là VARCHAR thì không thể sử dụng lại các câu lệnh do Máy chủ chuẩn bị. Và trong trường hợp này, chúng ta phải tạo lại câu lệnh của mình.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Nếu bạn đang thực hiện cùng một truy vấn, hãy đảm bảo rằng các kiểu dữ liệu trong cột của bạn không bị nhầm lẫn. Bạn cần coi chừng NULL. Đây là lỗi phổ biến chúng tôi gặp phải sau khi bắt đầu sử dụng preparedStatements

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Được rồi, đã bật. Có lẽ họ đã bắt được tài xế. Và năng suất giảm xuống. Mọi chuyện trở nên tồi tệ.

Làm thế nào điều này xảy ra? Đây có phải là một lỗi hoặc một tính năng? Thật không may, không thể hiểu đây là lỗi hay tính năng. Nhưng có một kịch bản rất đơn giản để tái hiện vấn đề này. Cô ấy hoàn toàn bất ngờ phục kích chúng tôi. Và nó bao gồm việc lấy mẫu theo đúng nghĩa đen từ một bảng. Tất nhiên, chúng tôi có nhiều yêu cầu như vậy hơn. Theo quy định, chúng bao gồm hai hoặc ba bảng, nhưng có một kịch bản phát lại như vậy. Lấy bất kỳ phiên bản nào từ cơ sở dữ liệu của bạn và chơi nó.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

https://gist.github.com/vlsi/df08cbef370b2e86a5c1

Vấn đề là chúng ta có hai cột, mỗi cột được lập chỉ mục. Có một triệu hàng trong một cột NULL. Và cột thứ hai chỉ có 20 dòng. Khi chúng tôi thực thi mà không có biến bị ràng buộc, mọi thứ đều hoạt động tốt.

Nếu chúng ta bắt đầu thực thi với các biến bị ràng buộc, tức là chúng ta thực thi dấu "?" hoặc “$1” cho yêu cầu của chúng ta, cuối cùng chúng ta sẽ nhận được gì?

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

https://gist.github.com/vlsi/df08cbef370b2e86a5c1

Lần thực hiện đầu tiên đúng như mong đợi. Cái thứ hai nhanh hơn một chút. Một cái gì đó đã được lưu vào bộ nhớ đệm. Thứ ba, thứ tư, thứ năm. Sau đó đập - và đại loại như thế. Và điều tồi tệ nhất là điều này xảy ra vào lần hành quyết thứ sáu. Ai biết rằng cần phải thực hiện đúng sáu lần hành quyết để hiểu kế hoạch thực hiện thực tế là gì?

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Ai có tội? Chuyện gì đã xảy ra thế? Cơ sở dữ liệu chứa tối ưu hóa. Và nó dường như được tối ưu hóa cho trường hợp chung. Và, theo đó, bắt đầu từ một thời điểm nào đó, cô ấy chuyển sang một kế hoạch chung, thật không may, kế hoạch này có thể khác. Nó có thể giống nhau hoặc có thể khác nhau. Và có một số loại giá trị ngưỡng dẫn đến hành vi này.

Bạn có thể làm gì về nó? Tất nhiên, ở đây việc giả định bất cứ điều gì sẽ khó khăn hơn. Có một giải pháp đơn giản mà chúng tôi sử dụng. Đây là +0, OFFSET 0. Chắc chắn bạn biết những giải pháp như vậy. Chúng tôi chỉ cần lấy nó và thêm “+0” vào yêu cầu và mọi thứ đều ổn. Tôi sẽ cho bạn thấy sau.

Và có một lựa chọn khác - xem xét kế hoạch cẩn thận hơn. Nhà phát triển không chỉ phải viết yêu cầu mà còn phải nói “giải thích phân tích” 6 lần. Nếu là 5 thì không được.

Và có một lựa chọn thứ ba - viết một lá thư cho các tin tặc pssql. Tôi đã viết, tuy nhiên, vẫn chưa rõ đây là lỗi hay tính năng.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

https://gist.github.com/vlsi/df08cbef370b2e86a5c1

Trong khi chúng tôi đang suy nghĩ xem đây là lỗi hay tính năng, hãy khắc phục nó. Hãy thực hiện yêu cầu của chúng tôi và thêm "+0". Mọi thứ đều ổn. Hai biểu tượng và bạn thậm chí không cần phải suy nghĩ xem nó như thế nào hoặc nó là gì. Rất đơn giản. Chúng tôi chỉ cấm cơ sở dữ liệu sử dụng chỉ mục trên cột này. Chúng tôi không có chỉ mục trên cột “+0” và thế là cơ sở dữ liệu không sử dụng chỉ mục, mọi thứ đều ổn.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Đây là quy tắc 6 giải thích. Bây giờ trong các phiên bản hiện tại, bạn phải thực hiện 6 lần nếu bạn có các biến bị ràng buộc. Nếu bạn không có biến bị ràng buộc, đây là những gì chúng tôi sẽ làm. Và cuối cùng chính yêu cầu này đã thất bại. Đó không phải là một điều khó khăn.

Có vẻ như, có thể có bao nhiêu? Lỗi ở đây, lỗi ở đó. Trên thực tế, lỗi có ở khắp mọi nơi.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Chúng ta hãy xem xét kỹ hơn. Ví dụ: chúng tôi có hai lược đồ. Sơ đồ A với bảng S và sơ đồ B với bảng S. Truy vấn - chọn dữ liệu từ một bảng. Chúng ta sẽ có gì trong trường hợp này? Chúng tôi sẽ có một lỗi. Chúng ta sẽ có tất cả những điều trên. Quy tắc là - lỗi ở khắp mọi nơi, chúng ta sẽ có tất cả những điều trên.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Bây giờ câu hỏi là: “Tại sao?” Có vẻ như có tài liệu nói rằng nếu chúng ta có một lược đồ thì sẽ có biến "search_path" cho chúng ta biết nơi cần tìm bảng. Có vẻ như có một biến số.

Vấn đề là gì? Vấn đề là các câu lệnh do máy chủ chuẩn bị không nghi ngờ rằng search_path có thể bị ai đó thay đổi. Giá trị này vẫn không đổi đối với cơ sở dữ liệu. Và một số phần có thể không tiếp thu được ý nghĩa mới.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Tất nhiên, điều này phụ thuộc vào phiên bản bạn đang thử nghiệm. Phụ thuộc vào mức độ nghiêm trọng của các bảng của bạn. Và phiên bản 9.1 sẽ chỉ thực hiện các truy vấn cũ. Các phiên bản mới có thể phát hiện lỗi và cho bạn biết rằng bạn có lỗi.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Đặt search_path + câu lệnh do máy chủ chuẩn bị =
kế hoạch được lưu trong bộ nhớ cache không được thay đổi loại kết quả

Làm thế nào để điều trị nó? Có một công thức đơn giản - đừng làm điều đó. Không cần thay đổi search_path khi ứng dụng đang chạy. Nếu bạn thay đổi, tốt hơn là tạo một kết nối mới.

Bạn có thể thảo luận, tức là mở, thảo luận, bổ sung. Có lẽ chúng ta có thể thuyết phục các nhà phát triển cơ sở dữ liệu rằng khi ai đó thay đổi một giá trị, cơ sở dữ liệu sẽ thông báo cho khách hàng về điều này: “Nhìn xem, giá trị của bạn đã được cập nhật tại đây. Có lẽ bạn cần phải thiết lập lại các câu lệnh và tạo lại chúng?” Bây giờ cơ sở dữ liệu hoạt động bí mật và không báo cáo theo bất kỳ cách nào rằng các câu lệnh đã thay đổi ở đâu đó bên trong.

Và tôi sẽ nhấn mạnh một lần nữa - đây là điều không điển hình đối với Java. Chúng ta sẽ thấy điều tương tự trong PL/pgSQL từng cái một. Nhưng nó sẽ được sao chép ở đó.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Hãy thử lựa chọn thêm dữ liệu. Chúng tôi chọn và chọn. Chúng tôi có một bảng có một triệu hàng. Mỗi dòng là một kilobyte. Khoảng một gigabyte dữ liệu. Và chúng tôi có bộ nhớ làm việc trong máy Java là 128 megabyte.

Chúng tôi, như được khuyến nghị trong tất cả các cuốn sách, sử dụng xử lý luồng. Nghĩa là, chúng tôi mở resultSet và đọc dữ liệu từ đó từng chút một. Nó sẽ hoạt động chứ? Nó sẽ rơi khỏi bộ nhớ? Bạn sẽ đọc một chút chứ? Hãy tin tưởng vào cơ sở dữ liệu, hãy tin tưởng vào Postgres. Chúng tôi không tin điều đó. Liệu chúng ta có bị OutOFMemory không? Ai đã trải nghiệm OutOfMemory? Ai đã sửa nó sau đó? Ai đó đã cố gắng sửa nó.

Nếu bạn có một triệu hàng, bạn không thể chỉ chọn và chọn. BẮT BUỘC/GIỚI HẠN là bắt buộc. Ai dành cho lựa chọn này? Và ai ủng hộ việc chơi với autoCommit?

Ở đây, như thường lệ, phương án bất ngờ nhất hóa ra lại đúng. Và nếu bạn đột nhiên tắt autoCommit thì sẽ có ích. Tại sao vậy? Khoa học không biết về điều này.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Nhưng theo mặc định, tất cả các máy khách kết nối với cơ sở dữ liệu Postgres đều tìm nạp toàn bộ dữ liệu. PGJDBC cũng không ngoại lệ về vấn đề này; nó chọn tất cả các hàng.

Có một biến thể về chủ đề FetchSize, tức là bạn có thể nói ở cấp độ một tuyên bố riêng rằng ở đây, vui lòng chọn dữ liệu theo 10, 50. Nhưng điều này không hoạt động cho đến khi bạn tắt autoCommit. Đã tắt autoCommit - nó bắt đầu hoạt động.

Nhưng việc xem qua mã và cài đặt setFetchSize ở mọi nơi là điều bất tiện. Do đó, chúng tôi đã thực hiện cài đặt sẽ hiển thị giá trị mặc định cho toàn bộ kết nối.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Đó là những gì chúng tôi đã nói. Tham số đã được cấu hình. Và chúng tôi đã nhận được gì? Nếu chúng tôi chọn số lượng nhỏ, ví dụ: nếu chúng tôi chọn 10 hàng cùng một lúc, thì chúng tôi sẽ có chi phí chung rất lớn. Do đó, giá trị này nên được đặt thành khoảng một trăm.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Tất nhiên, lý tưởng nhất là bạn vẫn phải học cách giới hạn nó theo byte, nhưng công thức là thế này: đặt defaultRowFetchSize thành hơn một trăm và hãy vui vẻ.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Hãy chuyển sang chèn dữ liệu. Việc chèn dễ dàng hơn, có nhiều lựa chọn khác nhau. Ví dụ: CHÈN, GIÁ TRỊ. Đây là một lựa chọn tốt. Bạn có thể nói “CHÈN CHỌN”. Trong thực tế nó là điều tương tự. Không có sự khác biệt về hiệu suất.

Sách nói rằng bạn cần thực thi một câu lệnh Batch, sách nói rằng bạn có thể thực thi các lệnh phức tạp hơn bằng một số dấu ngoặc đơn. Và Postgres có một tính năng tuyệt vời - bạn có thể thực hiện SAO CHÉP, tức là thực hiện nhanh hơn.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Nếu bạn đo lường nó, bạn lại có thể thực hiện một số khám phá thú vị. Chúng ta muốn nó hoạt động như thế nào? Chúng tôi muốn không phân tích cú pháp và không thực thi các lệnh không cần thiết.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Trong thực tế, TCP không cho phép chúng ta làm điều này. Nếu khách hàng đang bận gửi yêu cầu thì cơ sở dữ liệu sẽ không đọc các yêu cầu đó khi cố gắng gửi phản hồi cho chúng tôi. Kết quả cuối cùng là máy khách đợi cơ sở dữ liệu đọc yêu cầu và cơ sở dữ liệu đợi máy khách đọc phản hồi.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Và do đó, khách hàng buộc phải gửi gói đồng bộ hóa theo định kỳ. Tương tác mạng bổ sung, lãng phí thời gian hơn.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir SitnikovVà chúng ta càng thêm chúng vào, nó càng trở nên tồi tệ hơn. Trình điều khiển khá bi quan và thêm chúng khá thường xuyên, khoảng 200 dòng một lần, tùy thuộc vào kích thước của dòng, v.v.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

https://github.com/pgjdbc/pgjdbc/pull/380

Sẽ xảy ra trường hợp bạn chỉ sửa một dòng và mọi thứ sẽ tăng tốc gấp 10 lần. Nó xảy ra. Tại sao? Như thường lệ, một hằng số như thế này đã được sử dụng ở đâu đó. Và giá trị “128” có nghĩa là không sử dụng tính năng trộn.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Khai thác điểm chuẩn vi mô Java

Thật tốt là điều này không có trong phiên bản chính thức. Được phát hiện trước khi phát hành bắt đầu. Tất cả ý nghĩa tôi đưa ra đều dựa trên các phiên bản hiện đại.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Hãy thử nó. Chúng tôi đo lường InsertBatch một cách đơn giản. Chúng tôi đo InsertBatch nhiều lần, tức là cùng một kết quả nhưng có nhiều giá trị. Di chuyển khó khăn. Không phải ai cũng có thể làm được điều này, nhưng đây là một động tác đơn giản, dễ dàng hơn nhiều so với SAO CHÉP.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Bạn có thể thực hiện SAO CHÉP.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Và bạn có thể làm điều này trên các cấu trúc. Khai báo kiểu mặc định của Người dùng, truyền mảng và INSERT trực tiếp vào bảng.

Nếu bạn mở liên kết: pgjdbc/ubenchmsrk/InsertBatch.java, thì mã này có trên GitHub. Bạn có thể xem cụ thể những yêu cầu nào được tạo ra ở đó. Nó không quan trọng.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Chúng tôi đã phát động. Và điều đầu tiên chúng tôi nhận ra là việc không sử dụng hàng loạt là điều không thể. Tất cả các tùy chọn tạo khối đều bằng XNUMX, tức là thời gian thực hiện thực tế bằng XNUMX so với thực hiện một lần.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Chúng tôi chèn dữ liệu. Đó là một cái bàn rất đơn giản. Ba cột. Và chúng ta thấy gì ở đây? Chúng tôi thấy rằng cả ba tùy chọn này đều có thể so sánh được. Và COPY tất nhiên là tốt hơn.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Đây là lúc chúng ta chèn các mảnh vào. Khi chúng tôi nói rằng một giá trị GIÁ TRỊ, hai giá trị GIÁ TRỊ, ba giá trị GIÁ TRỊ hoặc chúng tôi chỉ ra 10 giá trị trong số đó được phân tách bằng dấu phẩy. Bây giờ nó chỉ nằm ngang. 1, 2, 4, 128. Có thể thấy Batch Insert được vẽ bằng màu xanh lam khiến anh cảm thấy dễ chịu hơn rất nhiều. Nghĩa là, khi bạn chèn từng cái một hoặc thậm chí khi bạn chèn bốn cái cùng một lúc, nó sẽ tốt gấp đôi, đơn giản vì chúng tôi đã nhồi nhét thêm một chút vào GIÁ TRỊ. Ít thao tác EXECUTE hơn.

Sử dụng COPY trên khối lượng nhỏ là điều cực kỳ không mấy hứa hẹn. Tôi thậm chí còn không vẽ hai cái đầu tiên. Họ lên thiên đường, tức là những con số màu xanh lá cây này dành cho SAO CHÉP.

COPY nên được sử dụng khi bạn có ít nhất một trăm hàng dữ liệu. Chi phí mở kết nối này là lớn. Và thành thật mà nói, tôi không đào sâu theo hướng này. Tôi đã tối ưu hóa Hàng loạt chứ không phải SAO CHÉP.

Chúng ta làm gì tiếp theo? Chúng tôi đã thử nó. Chúng tôi hiểu rằng chúng tôi cần sử dụng các cấu trúc hoặc một cách viết thông minh kết hợp nhiều ý nghĩa.

PostgreSQL và JDBC vắt hết nước trái cây. Vladimir Sitnikov

Bạn nên rút ra điều gì từ báo cáo ngày hôm nay?

  • Chuẩn bị sẵn sàng là tất cả mọi thứ của chúng tôi. Điều này mang lại rất nhiều cho năng suất. Nó tạo ra một thất bại lớn trong thuốc mỡ.
  • Và bạn cần thực hiện GIẢI THÍCH PHÂN TÍCH 6 lần.
  • Và chúng tôi cần pha loãng OFFSET 0 và các thủ thuật như +0 để sửa phần trăm còn lại của các truy vấn có vấn đề.

Nguồn: www.habr.com

Thêm một lời nhận xét