2012-02-14 38 views
6

Trong PostgreSQL, khi nào các truy vấn (SELECT) được lên kế hoạch?Khi nào các truy vấn (SELECT) được lên kế hoạch?

Có:

  1. tại statement-chuẩn bị thời gian, hoặc
  2. lúc bắt đầu chế biến SELECT, hoặc
  3. cái gì khác

Lý do tôi hỏi là có là một câu hỏi Stackoverflow: same query, two different ways, vastly different performance

Rất nhiều người dường như đang nghĩ rằng t truy vấn của anh ta được lên kế hoạch khác nhau bởi vì trong một trường hợp truy vấn chứa một chuỗi ký tự ('foo') và trong một trường hợp khác, nó là một trình giữ chỗ (?).

Bây giờ suy nghĩ của tôi là đây là một cá trích đỏ, vì truy vấn không được lên kế hoạch vào thời gian chuẩn bị tuyên bố, nhưng thực sự được lên kế hoạch vào thời gian SELECT. Vì vậy, nói, tôi có thể chuẩn bị một câu lệnh với một trình giữ chỗ, sau đó chạy truy vấn nhiều lần với các giá trị giới hạn khác nhau, và trình hoạch định truy vấn sẽ được chạy cho mỗi giá trị ràng buộc khác nhau.

Tôi nghi ngờ rằng question linked above nén xuống kiểu dữ liệu PostgreSQL của giá trị, trong trường hợp của một chữ cái 'foo' được biết là một chuỗi, nhưng trong trường hợp trình giữ chỗ, loại không thể được chia , như vậy là thông qua để kế hoạch truy vấn như một số loại kỳ lạ, mà nó không thể tạo ra một kế hoạch hiệu quả cho. Trong trường hợp đó, vấn đề không phải là truy vấn đang được lên kế hoạch khác nhau bởi vì giá trị là một trình giữ chỗ (tại thời điểm chuẩn bị tuyên bố) mỗi se nhưng giá trị đó được chuyển đến truy vấn dưới dạng loại PostgreSQL khác và là những gì ảnh hưởng đến kế hoạch truy vấn. Để khắc phục điều này đơn giản chỉ là vấn đề ràng buộc trình giữ chỗ với một khai báo kiểu khai báo thích hợp.

+1

Câu hỏi hay! Điều này rất cụ thể về DBMS; DBMS khác nhau đưa ra các câu trả lời khác nhau (hơi). Kết quả thực có thể khác nhau đáng kể. Informix hỗ trợ một 'OPEN cursor USING ... WITH REOPTIMIZATION' mà không phải reparse SQL (tiết kiệm thời gian) nhưng làm lại kế hoạch truy vấn cho tập các tham số hiện tại. Điều đó lại khác với hầu hết các DBMS. –

+0

Có. Câu hỏi này được chứng minh là gây tranh cãi đáng ngạc nhiên.Chúng tôi có upvotes và một downvote về câu hỏi và một trong những câu trả lời. – zgpmax

+0

@hochgurgler: Nghi ngờ của bạn về loại không phù hợp là do chính nó là một mối quan tâm hợp lệ, PostgreSQL _has_ một số vấn đề đã biết ở đây. Nhưng xem xét phần đầu tiên của câu hỏi tôi nghĩ rằng hai vấn đề này không nên được trộn lẫn và phần thứ hai sẽ được xử lý tốt hơn bằng một câu hỏi riêng biệt. Bạn vui lòng chia nó? –

Trả lời

10

Tôi không thể nói về giao diện Perl phía máy khách nhưng tôi có thể làm sáng tỏ một số thứ ở phía máy chủ PostgreSQL.

PostgreSQL đã có các câu lệnh chuẩn bị và phát biểu chưa chuẩn bị. Các câu lệnh không chuẩn bị được phân tích cú pháp, lập kế hoạch và thực hiện ngay lập tức. Họ cũng làm không thay thế thông số hỗ trợ. Trên một đồng bằng psql vỏ bạn có thể hiển thị kế hoạch truy vấn của họ như thế này:

tmpdb> explain select * from sometable where flag = true; 

Mặt khác có những chuẩn bị phát biểu: Họ thường (xem "ngoại lệ" dưới đây) phân tích và lên kế hoạch trong một bước và thực hiện trong một bước thứ hai. Chúng có thể được thực hiện lại nhiều lần với các thông số khác nhau, vì chúng làm thay thế thông số hỗ trợ.Tương đương trong psql là thế này:

tmpdb> prepare foo as select * from sometable where flag = $1; 
tmpdb> explain execute foo(true); 

Bạn có thể thấy, đó là kế hoạch là khác biệt so với kế hoạch trong báo cáo không chuẩn bị, bởi vì kế hoạch đã diễn ra đã có trong giai đoạn prepare như mô tả trong doc cho PREPARE:

Khi lệnh PREPARE được thực thi, báo cáo kết quả cụ thể là phân tích cú pháp , viết lại, và lên kế hoạch. Khi một lệnh EXECUTE là sau đó được ban hành, câu lệnh đã chuẩn bị chỉ cần được thực hiện. Do đó, các giai đoạn phân tích cú pháp, viết lại và lập kế hoạch chỉ được thực hiện một lần, thay vì mỗi khi câu lệnh được thực thi.

này cũng có nghĩa, rằng kế hoạch là KHÔNG tối ưu hóa cho các thông số thay: Trong ví dụ đầu tiên có thể sử dụng một chỉ số cho flag vì PostgreSQL biết rằng trong vòng một triệu mục chỉ có mười có giá trị true. Lý do này là không thể khi PostgreSQL sử dụng một câu lệnh chuẩn bị. Trong trường hợp đó, một kế hoạch được tạo ra sẽ làm việc cho tất cả các giá trị tham số có thể tốt nhất có thể. Điều này có thể loại trừ chỉ mục được đề cập vì tìm nạp phần tốt hơn của bảng hoàn chỉnh qua truy cập ngẫu nhiên (do chỉ mục) chậm hơn so với quét tuần tự đơn giản. Tài liệu PREPARE xác nhận điều này:

Trong một số trường hợp, kế hoạch truy vấn được tạo ra cho câu lệnh chuẩn bị sẽ kém hơn so với kế hoạch truy vấn đã được chọn nếu tuyên bố đã được gửi và thực hiện bình thường. Điều này là do khi tuyên bố được lên kế hoạch và kế hoạch cố gắng xác định kế hoạch truy vấn tối ưu, các giá trị thực tế của bất kỳ tham số nào được chỉ định trong câu lệnh không có sẵn. PostgreSQL thu thập số liệu thống kê về phân phối dữ liệu trong bảng và có thể sử dụng các giá trị không đổi trong một câu lệnh để đoán về kết quả có khả năng thực hiện câu lệnh. Vì dữ liệu này không có sẵn khi lập kế hoạch các câu lệnh chuẩn bị với các tham số, kế hoạch đã chọn có thể là tối ưu.

BTW - Về kế hoạch bộ nhớ đệm PREPARE doc cũng có một cái gì đó để nói:

báo cáo chuẩn bị chỉ kéo dài trong suốt thời gian của phiên cơ sở dữ liệu hiện hành. Khi phiên kết thúc, câu lệnh đã chuẩn bị bị lãng quên, vì vậy nó phải được tạo lại trước khi được sử dụng lại.

Cũng không có bộ nhớ đệm gói tự động và không lưu vào bộ nhớ đệm/tái sử dụng qua nhiều kết nối.

NGOẠI TRỪ: Tôi đã đề cập "thường". Các ví dụ psql được hiển thị không phải là thứ mà một bộ điều hợp khách hàng như Perl DBI thực sự sử dụng. Nó sử dụng một số protocol nhất định. Ở đây thuật ngữ "truy vấn đơn giản" tương ứng với "truy vấn không chuẩn bị" trong psql, cụm từ "extended query" tương ứng với "truy vấn đã chuẩn bị" với một ngoại lệ: Có sự phân biệt giữa (một) "tuyên bố chưa đặt tên" và (có thể nhiều) " báo cáo có tên ". Về các tuyên bố có tên là doc nói:

Các câu lệnh được chuẩn bị có tên cũng có thể được tạo và truy cập ở cấp lệnh SQL, sử dụng PREPARE và EXECUTE.

và cũng: lập kế hoạch

Query cho tên đối tượng chuẩn bị-tuyên bố xảy ra khi nhắn Parse được xử lý.

Vì vậy, trong trường hợp này, việc lập kế hoạch được thực hiện mà không có tham số như được mô tả ở trên cho PREPARE - không có gì mới.

Ngoại lệ được đề cập là "tuyên bố chưa đặt tên". Tài liệu cho biết:

Tuyên bố được chuẩn bị chưa được đặt tên cũng được lên kế hoạch trong khi xử lý Parse nếu thông báo Parse xác định không có tham số. Nhưng nếu có các tham số, lập kế hoạch truy vấn xảy ra mỗi khi các tham số Bind được cung cấp. Điều này cho phép người lập kế hoạch sử dụng các giá trị thực tế của các tham số được cung cấp bởi mỗi thông điệp Bind, thay vì sử dụng các ước tính chung chung.

Và đây là lợi ích: Mặc dù câu lệnh chưa được đặt tên là "đã chuẩn bị" (nghĩa là có thể thay thế tham số), nó cũng có thể điều chỉnh kế hoạch truy vấn.

BTW: Việc xử lý chính xác câu lệnh chưa đặt tên đã thay đổi nhiều lần trong các phiên bản trước của máy chủ PostgreSQL. Bạn có thể tra cứu các tài liệu cũ để biết chi tiết nếu bạn thực sự muốn.

Lý - Perl/bất kỳ khách hàng:

Làm thế nào một client như Perl sử dụng giao thức là một câu hỏi hoàn toàn khác nhau. Một số khách hàng như trình điều khiển JDBC cho Java về cơ bản nói: Ngay cả khi lập trình viên sử dụng một câu lệnh đã chuẩn bị, thì năm thực thi đầu tiên (hoặc hơn) được ánh xạ nội bộ tới một "truy vấn đơn giản" (tức là không chuẩn bị hiệu quả), sau đó trình điều khiển chuyển sang " câu lệnh có tên ".

Vì vậy, một khách hàng có những lựa chọn này:

  • Force (lại) lên kế hoạch cho từng thời gian bằng cách sử dụng "truy vấn đơn giản" giao thức.
  • Lập kế hoạch một lần, thực hiện nhiều lần bằng giao thức "truy vấn mở rộng" và "tuyên bố tên" (kế hoạch có thể xấu vì lập kế hoạch được thực hiện mà không có tham số).
  • Parse một lần, kế hoạch cho từng thực hiện (với phiên bản PostgreSQL hiện hành) bằng cách sử dụng các "truy vấn mở rộng" giao thức và "tuyên bố vô danh" và tuân theo một số điều hơn (cung cấp một số params trong "phân tích" tin nhắn)
  • Chơi các thủ thuật hoàn toàn khác nhau như trình điều khiển JDBC.

Hiện tại Perl là gì: Tôi không biết. Nhưng đề cập đến "cá trích đỏ" không phải là rất khó xảy ra.

+0

+1 nhưng đáng giá hơn! –

+0

+1 Rất nhiều thông tin. –

+0

Bán cập nhật: Kể từ phiên bản 9.2, quy hoạch có một chút khác biệt. Về cơ bản, các truy vấn chuẩn bị sẵn sàng sẽ được lên kế hoạch cho mỗi lời gọi bằng cách sử dụng các tham số thực tế. Chỉ sau khi một số invocations đã chứng minh, rằng các kế hoạch không khác nhau nhiều, một kế hoạch chung được sử dụng. –

Các vấn đề liên quan