Hiệu suất chức năng


46

Đến từ nền tảng MySQL, nơi hiệu suất thủ tục được lưu trữ (bài viết cũ hơn)khả năng sử dụng là đáng nghi ngờ, tôi đang đánh giá PostgreQuery cho một sản phẩm mới cho công ty của tôi.

Một trong những điều tôi muốn làm là chuyển một số logic ứng dụng vào các thủ tục được lưu trữ, vì vậy tôi ở đây yêu cầu DO và KHÔNG (cách thực hành tốt nhất) về việc sử dụng các hàm trong PostgreQuery (9.0), đặc biệt liên quan đến các cạm bẫy hiệu năng.


bạn có nghĩa là bạn không muốn câu trả lời đề cập đến bất cứ điều gì không liên quan đến hiệu suất?
Jack Douglas

Chris Travers viết blog rất nhiều về những lợi ích của việc sử dụng các thủ tục được lưu trữ, ví dụ ở đây: ledgersmbdev.blogspot.de/2012/07/ và và tại đây: ledgersmbdev.blogspot.de/2012/07/ chỉ cần lướt qua blog của mình, có một rất nhiều bài viết thú vị về chủ đề này.
a_horse_with_no_name

Câu trả lời:


51

Nói một cách chính xác, thuật ngữ "các thủ tục được lưu trữ" chỉ đến các thủ tục SQL trong Postgres, được giới thiệu với Postgres 11. Liên quan:

Ngoài ra còn có các chức năng , làm gần như nhưng không hoàn toàn giống nhau, và những chức năng đã có từ đầu.

Chức năng với LANGUAGE sqlcơ bản hỗ trợ file batch với các lệnh đơn giản SQL trong một wrapper chức năng (và do đó nguyên tử, luôn luôn chạy bên trong một đơn giao dịch) chấp nhận các thông số. Tất cả các câu lệnh trong một hàm SQL được lập kế hoạch cùng một lúc , khác biệt một cách tinh tế so với việc thực hiện một câu lệnh khác và có thể ảnh hưởng đến thứ tự thực hiện các khóa.

Đối với bất cứ điều gì hơn, ngôn ngữ trưởng thành nhất là PL / pgSQL ( LANGUAGE plpgsql). Nó hoạt động tốt và đã được cải thiện với mỗi bản phát hành trong thập kỷ qua, nhưng nó phục vụ tốt nhất như keo cho các lệnh SQL. Nó không có nghĩa là cho các tính toán nặng nề (ngoài các lệnh SQL).

Các hàm PL / pgSQL thực thi các truy vấn như các câu lệnh đã chuẩn bị . Việc sử dụng lại các gói truy vấn được lưu trong bộ nhớ cache sẽ cắt giảm một số chi phí lập kế hoạch và làm cho chúng nhanh hơn một chút so với các câu lệnh SQL tương đương, có thể là một hiệu ứng đáng chú ý tùy thuộc vào hoàn cảnh. Nó cũng có thể có tác dụng phụ như trong câu hỏi liên quan này:

Điều này mang những ưu điểm và nhược điểm của các tuyên bố đã chuẩn bị - như được thảo luận trong hướng dẫn . Đối với các truy vấn trên các bảng có phân phối dữ liệu không thường xuyên và các tham số khác nhau, SQL độngEXECUTEthể hoạt động tốt hơn khi mức tăng từ kế hoạch thực hiện được tối ưu hóa cho (các) tham số đã cho vượt xa chi phí lập kế hoạch lại.

Vì các kế hoạch thực hiện chung của Postgres 9.2 vẫn được lưu trong bộ nhớ cache cho phiên, nhưng, trích dẫn hướng dẫn :

Điều này xảy ra ngay lập tức cho các báo cáo chuẩn bị không có tham số; mặt khác, nó chỉ xảy ra sau năm lần thực hiện trở lên tạo ra các kế hoạch mà chi phí trung bình ước tính (bao gồm cả chi phí kế hoạch) đắt hơn so với ước tính chi phí kế hoạch chung.

Chúng tôi nhận được tốt nhất của cả hai thế giới hầu hết thời gian (ít hơn một số chi phí bổ sung) mà không (ab) sử dụng EXECUTE. Chi tiết về những gì mới trong PostgreSQL 9.2 của PostgreSQL Wiki .

Postgres 12 giới thiệu biến máy chủplan_cache_mode bổ sung để buộc các gói chung hoặc tùy chỉnh. Đối với trường hợp đặc biệt, sử dụng cẩn thận.

Bạn có thể thắng lớn với các chức năng phía máy chủ ngăn các chuyến đi khứ hồi bổ sung đến máy chủ cơ sở dữ liệu từ ứng dụng của bạn. Yêu cầu máy chủ thực thi càng nhiều càng tốt cùng một lúc và chỉ trả về một kết quả được xác định rõ.

Tránh lồng các hàm phức tạp, đặc biệt là các hàm bảng ( RETURNING SETOF recordhoặc TABLE (...)). Các hàm là các hộp đen đóng vai trò là rào cản tối ưu hóa cho trình hoạch định truy vấn. Chúng được tối ưu hóa một cách riêng biệt, không phải trong bối cảnh của truy vấn bên ngoài, điều này làm cho việc lập kế hoạch đơn giản hơn, nhưng có thể dẫn đến các kế hoạch ít hơn hoàn hảo. Ngoài ra, chi phí và kích thước kết quả của các chức năng không thể được dự đoán một cách đáng tin cậy.

Các ngoại lệ cho quy tắc này là các hàm SQL đơn giản ( LANGUAGE sql), mà có thể được "inlined" - nếu một số điều kiện tiên quyết được đáp ứng . Đọc thêm về cách trình lập kế hoạch truy vấn hoạt động trong bản trình bày này của Neil Conway (công cụ nâng cao).

Trong PostgreSQL, một chức năng luôn tự động chạy trong một giao dịch . Tất cả đều thành công hoặc không có gì. Nếu một ngoại lệ xảy ra, mọi thứ sẽ được khôi phục. Nhưng có xử lý lỗi ...

Đó cũng là lý do tại sao các chức năng không chính xác là "thủ tục được lưu trữ" (mặc dù thuật ngữ đó đôi khi được sử dụng, gây hiểu nhầm). Một số lệnh như VACUUM, CREATE INDEX CONCURRENTLYhoặc CREATE DATABASEkhông thể chạy bên trong khối giao dịch, vì vậy chúng không được phép trong các chức năng. (Tuy nhiên, trong các thủ tục SQL, kể từ Postgres 11. Điều đó có thể được thêm vào sau.)

Tôi đã viết hàng ngàn chức năng plpgsql trong những năm qua.


2
@nhahtdh: "giao dịch tự động" không phải là một thuật ngữ kỹ thuật. Đó chỉ là một cách nói khó nghe tao nhã .. những gì nó nói bây giờ sau khi tôi làm rõ. Không phải là một giao dịch tự trị ở tất cả. "tự trị" chỉ là một từ tương tự.
Erwin Brandstetter

4
Câu trả lời của bạn được tổng hợp từ đây và SO có thể là một cẩm nang thực hành tốt nhất của PostGreSQL.
Davos

10

Một số DO:

  • Sử dụng SQL làm ngôn ngữ hàm khi có thể, vì PG có thể nội tuyến các câu lệnh
  • Sử dụng IMMUTABLE / STABLE / VOLATILE một cách chính xác, vì PG có thể lưu trữ kết quả nếu nó không thay đổi hoặc ổn định
  • Sử dụng chính xác STRICT, vì PG chỉ có thể trả về null nếu bất kỳ đầu vào nào là null thay vì chạy chức năng
  • Hãy xem xét PL / V8 khi bạn không thể sử dụng SQL làm ngôn ngữ hàm. Nó nhanh hơn PL / pgSQL trong một số thử nghiệm không khoa học mà tôi đã chạy
  • Sử dụng LISTEN / THÔNG BÁO cho các quy trình chạy dài hơn có thể xảy ra ngoài giao dịch
  • Cân nhắc sử dụng các hàm để thực hiện phân trang vì phân trang dựa trên khóa có thể nhanh hơn phân trang dựa trên LIMIT
  • Hãy chắc chắn rằng bạn kiểm tra đơn vị chức năng của bạn

Đây là lần đầu tiên tôi thấy tuyên bố rằng PL / V8 nhanh hơn PL / pgSQL. Bạn có bất kỳ số liệu (được công bố) để hỗ trợ đó?
a_horse_with_no_name

@a_horse_with_no_name không, tôi không. Như tôi đã nói, tôi đã làm một vài bài kiểm tra không khoa học. Họ chủ yếu là logic, không truy cập dữ liệu. Tôi sẽ thử làm một số bài kiểm tra lặp lại qua xmas và đăng lại ở đây.
Neil McGuigan

@a_horse_with_no_name đây là một ví dụ nhanh chóng cho FizzBuzz plv8 vs plpgsql: blog.databasepotypes.com/2014/08/plv8-vs-plpgsql.html
Neil McGuigan

8

Nói chung, việc di chuyển logic ứng dụng vào cơ sở dữ liệu sẽ có nghĩa là nó nhanh hơn - sau tất cả, nó sẽ chạy gần hơn với dữ liệu.

Tôi tin rằng (nhưng không chắc chắn 100%) rằng các hàm ngôn ngữ SQL nhanh hơn các hàm sử dụng bất kỳ ngôn ngữ nào khác vì chúng không yêu cầu chuyển ngữ cảnh. Nhược điểm là không cho phép logic thủ tục.

PL / pgSQL là ngôn ngữ hoàn thiện và hoàn thiện nhất trong các ngôn ngữ được tích hợp - nhưng để thực hiện, C có thể được sử dụng (mặc dù nó sẽ chỉ có lợi cho các chức năng chuyên sâu tính toán)


7

Bạn có thể thực hiện một số nội dung rất thú vị bằng cách sử dụng các hàm do người dùng xác định (UDF) trong postgresql. Chẳng hạn, có hàng tá ngôn ngữ có thể bạn có thể sử dụng. Các pl / sql và pl / pss được tích hợp đều có khả năng và đáng tin cậy và sử dụng phương pháp hộp cát để ngăn người dùng làm bất cứ điều gì quá nguy hiểm. Các UDF được viết bằng C cung cấp cho bạn sức mạnh và hiệu suất tối đa, vì chúng chạy trong cùng bối cảnh với chính cơ sở dữ liệu. Tuy nhiên, nó giống như chơi với lửa, bởi vì ngay cả những lỗi nhỏ cũng có thể gây ra vấn đề lớn, với các phụ trợ bị hỏng hoặc dữ liệu bị hỏng. Các ngôn ngữ pl yêu cầu, như pl / R, pl / ruby, pl / perl, v.v. cung cấp cho bạn khả năng viết cả hai lớp cơ sở dữ liệu và ứng dụng trong cùng một ngôn ngữ. Điều này có thể hữu ích, vì điều đó có nghĩa là bạn không phải dạy một lập trình viên perl java hoặc pl / pssql, v.v. để viết UDF.

Cuối cùng, có ngôn ngữ pl / proxy . Ngôn ngữ UDF này cho phép bạn chạy ứng dụng của mình trên hàng chục máy chủ postgresql phụ trợ cho mục đích mở rộng. Nó được phát triển bởi những người tốt ở Skype và về cơ bản cho phép giải pháp mở rộng theo chiều ngang của một người nghèo. Thật dễ dàng để viết là tốt.

Bây giờ, như vấn đề hiệu suất. Đây là một khu vực màu xám. Bạn đang viết một ứng dụng cho một người? Hay cho 1.000? hay với giá 10.000.000? Cách bạn xây dựng ứng dụng của mình và sử dụng UDF sẽ phụ thuộc rất nhiều vào cách bạn cố gắng mở rộng quy mô. Nếu bạn đang viết cho hàng ngàn và hàng ngàn người dùng, thì điều chính bạn muốn làm là giảm tải cho db càng nhiều càng tốt. Các UDF làm giảm lượng dữ liệu được chuyển ra và quay lại cơ sở dữ liệu sẽ giúp giảm tải IO. Tuy nhiên, nếu chúng bắt đầu tăng tải CPU, thì chúng có thể là một vấn đề. Nói chung, giảm tải IO là ưu tiên hàng đầu và đảm bảo các UDF hoạt động hiệu quả để không làm quá tải CPU của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.