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

PostgreSQL GIẢI THÍCH - Chi phí Truy vấn là gì?

Hiểu chi phí Postgres GIẢI THÍCH

EXPLAIN rất hữu ích để hiểu hiệu suất của một truy vấn Postgres. Nó trả về kế hoạch thực thi được tạo bởi trình lập kế hoạch truy vấn PostgreSQL cho một câu lệnh nhất định. EXPLAIN lệnh chỉ định xem các bảng được tham chiếu trong một câu lệnh sẽ được tìm kiếm bằng cách sử dụng quét chỉ mục hay quét tuần tự.

Một số điều đầu tiên bạn sẽ nhận thấy khi xem lại đầu ra của EXPLAIN là số liệu thống kê chi phí, vì vậy bạn sẽ tự hỏi ý nghĩa của chúng, cách chúng được tính toán và cách chúng được sử dụng.

Nói tóm lại, công cụ lập kế hoạch truy vấn PostgreSQL đang ước tính lượng thời gian truy vấn sẽ mất (trong một đơn vị tùy ý), với cả chi phí khởi động và tổng chi phí cho mỗi hoạt động. Thêm về điều đó sau. Khi có nhiều tùy chọn để thực hiện một truy vấn, nó sẽ sử dụng các chi phí này để chọn tùy chọn rẻ nhất và do đó hy vọng là nhanh nhất.

Chi phí được tính theo đơn vị nào?

Các chi phí được tính theo một đơn vị tùy ý. Một sự hiểu lầm phổ biến là chúng tính bằng mili giây hoặc một số đơn vị thời gian khác, nhưng không phải vậy.

Các đơn vị chi phí được cố định (theo mặc định) vào một trang tuần tự được đọc với giá 1,0 đơn vị (seq_page_cost ). Mỗi hàng được xử lý thêm 0,01 (cpu_tuple_cost ) và mỗi lần đọc trang không tuần tự sẽ thêm 4,0 (random_page_cost ). Có nhiều hằng số khác như thế này, tất cả đều có thể cấu hình được. Cái cuối cùng đó là một ứng cử viên đặc biệt phổ biến, ít nhất là trên phần cứng hiện đại. Chúng tôi sẽ xem xét vấn đề đó sau một chút.

Chi phí Khởi động

Những con số đầu tiên bạn nhìn thấy sau cost= được gọi là "chi phí khởi động". Đây là ước tính về khoảng thời gian sẽ mất để tìm nạp hàng đầu tiên . Như vậy, chi phí khởi động của một hoạt động bao gồm cả chi phí của các con của nó.

Đối với quét tuần tự, chi phí khởi động nói chung sẽ gần bằng 0, vì nó có thể bắt đầu tìm nạp các hàng ngay lập tức. Đối với thao tác sắp xếp, nó sẽ cao hơn vì một phần lớn công việc cần được thực hiện trước khi các hàng có thể bắt đầu được trả lại.

Để xem một ví dụ, hãy tạo một bảng thử nghiệm đơn giản với 1000 tên người dùng:

 TẠO người dùng BẢNG (id bigint ĐƯỢC TẠO LUÔN LÀ TỪ KHÓA CHÍNH CỦA IDENTITY, văn bản tên người dùng KHÔNG ĐẦY ĐỦ); CHÈN VÀO người dùng (tên người dùng) CHỌN 'người' || nFROM create_series (1, 1000) AS n; ANALYZE người dùng; 

Hãy xem xét một kế hoạch truy vấn đơn giản, với một vài thao tác:

 GIẢI THÍCH CHỌN * TỪ người dùng ĐẶT HÀNG THEO tên người dùng; KẾ HOẠCH QUERY | ----------------------------------- --------------------------- + Sắp xếp (chi phí =66,83..69,33 hàng =1000 chiều rộng =17) | Khóa sắp xếp:tên người dùng | -> Quét Seq trên người dùng (giá =0,00..17,00 hàng =1000 chiều rộng =17) | 

Trong kế hoạch truy vấn ở trên, như mong đợi, chi phí thực thi câu lệnh ước tính cho Seq Scan0.00 và cho Sort66.83 .

Tổng chi phí

Thống kê chi phí thứ hai, sau chi phí khởi động và hai dấu chấm, được gọi là "tổng chi phí". Đây là ước tính về thời gian để trả về tất cả các hàng .

Hãy xem lại kế hoạch truy vấn mẫu đó:

 KẾ HOẠCH QUERY | -------------------------------------------- ------------------ + Sắp xếp (giá =66,83..69,33 hàng =1000 chiều rộng =17) | Khóa sắp xếp:tên người dùng | -> Quét Seq trên người dùng (giá =0,00..17,00 hàng =1000 chiều rộng =17) | 

Chúng ta có thể thấy rằng tổng chi phí của Seq Scan hoạt động là 17.00 . Đối với Sort hoạt động là 69,33, không cao hơn nhiều so với chi phí khởi động của nó (như dự kiến).

Tổng chi phí thường bao gồm chi phí của các hoạt động trước chúng. Ví dụ:tổng chi phí của hoạt động Sắp xếp ở trên bao gồm chi phí của Quét tuần tự.

Một ngoại lệ quan trọng là LIMIT các mệnh đề mà người lập kế hoạch sử dụng để ước tính xem nó có thể hủy bỏ sớm hay không. Nếu nó chỉ cần một số lượng nhỏ hàng, các điều kiện phổ biến, nó có thể tính toán rằng lựa chọn quét đơn giản hơn sẽ rẻ hơn (có khả năng nhanh hơn).

Ví dụ:

 GIẢI THÍCH CHỌN * TỪ người dùng GIỚI HẠN 1; KẾ HOẠCH QUERY | ------------------------------------ -------------------------- + Giới hạn (chi phí =0,00..0,02 hàng =1 chiều rộng =17) | -> Quét Seq trên người dùng (giá =0,00..17,00 hàng =1000 chiều rộng =17) | 

Như bạn có thể thấy, tổng chi phí được báo cáo trên nút Seq Scan vẫn là 17,00, nhưng toàn bộ chi phí của hoạt động Giới hạn được báo cáo là 0,02. Điều này là do người lập kế hoạch dự kiến ​​rằng nó sẽ chỉ phải xử lý 1 hàng trong số 1000, vì vậy chi phí, trong trường hợp này, được ước tính là hàng thứ 1000 trên tổng số.

Cách tính chi phí

Để tính toán những chi phí này, công cụ lập kế hoạch truy vấn Postgres sử dụng cả hằng số (một số hằng số mà chúng tôi đã thấy) và siêu dữ liệu về nội dung của cơ sở dữ liệu. Siêu dữ liệu thường được gọi là "thống kê".

Thống kê được thu thập qua ANALYZE (đừng nhầm với EXPLAIN tham số cùng tên) và được lưu trữ trong pg_statistic . Chúng cũng được làm mới tự động như một phần của autovacuum.

Những thống kê này bao gồm một số thứ rất hữu ích, chẳng hạn như số lượng hàng gần như mà mỗi bảng có và giá trị phổ biến nhất trong mỗi cột là gì.

Hãy xem một ví dụ đơn giản, sử dụng cùng một dữ liệu truy vấn như trước đây:

 GIẢI THÍCH số lượng CHỌN (*) TỪ người dùng; KẾ HOẠCH QUERY | ----------------------------------- -------------------------- + Tổng hợp (chi phí =19.50..19.51 hàng =1 chiều rộng =8) | -> Quét Seq trên người dùng (giá =0,00..17,00 hàng =1000 chiều rộng =0) | 

Trong trường hợp của chúng tôi, thống kê của người lập kế hoạch đề xuất dữ liệu cho bảng được lưu trữ trong 7 trang (hoặc khối) và 1000 hàng sẽ được trả lại. Thông số chi phí seq_page_cost , cpu_tuple_costcpu_operator_cost được để ở giá trị mặc định là 1 , 0.010.0025 tương ứng.

Như vậy, tổng chi phí Quét Seq được tính như sau:

 Tổng chi phí của Seq Scan =(số lần đọc trang tuần tự ước tính * seq_page_cost) + (số hàng ước tính được trả về * cpu_tuple_cost) =(7 * 1) + (1000 * 0.01) =7 + 10.00 =17.00 

Và đối với Tổng hợp là:

 Tổng chi phí Tổng hợp =(chi phí Quét tuần tự) + (các hàng ước tính được xử lý * cpu_operator_cost) + (các hàng ước tính được trả về * cpu_tuple_cost) =(17,00) + (1000 * 0,0025) + (1 * 0,01) =17,00 + 2,50 + 0,01 =19,51 

Cách người lập kế hoạch sử dụng chi phí

Vì chúng tôi biết Postgres sẽ chọn kế hoạch truy vấn có tổng chi phí thấp nhất, chúng tôi có thể sử dụng kế hoạch đó để cố gắng hiểu các lựa chọn mà nó đã thực hiện. Ví dụ:nếu một truy vấn không sử dụng chỉ mục mà bạn mong đợi, bạn có thể sử dụng các cài đặt như enable_seqscan để ngăn cản ồ ạt các lựa chọn kế hoạch truy vấn nhất định. Đến đây, bạn sẽ không ngạc nhiên khi biết rằng các cài đặt như thế này hoạt động bằng cách tăng chi phí!
Số hàng là một phần cực kỳ quan trọng trong ước tính chi phí. Chúng được sử dụng để tính toán ước tính cho các lệnh tham gia khác nhau, thuật toán tham gia, loại quét và hơn thế nữa. Ước tính chi phí hàng được đưa ra nhiều có thể dẫn đến ước tính chi phí bị chênh lệch nhiều, điều này cuối cùng có thể dẫn đến việc đưa ra lựa chọn kế hoạch dưới mức tối ưu.

Sử dụng GIẢI THÍCH PHÂN TÍCH để có được kế hoạch truy vấn

Khi bạn viết câu lệnh SQL trong PostgreSQL, ANALYZE là chìa khóa để tối ưu hóa các truy vấn, làm cho chúng nhanh hơn và hiệu quả hơn. Ngoài việc hiển thị kế hoạch truy vấn và ước tính PostgreSQL, EXPLAIN ANALYZE tùy chọn thực hiện truy vấn (hãy cẩn thận với UPDATEDELETE !), và hiển thị thời gian thực hiện thực tế và số hàng đếm cho mỗi bước trong quy trình thực thi. Điều này là cần thiết để theo dõi hiệu suất SQL.

Bạn có thể sử dụng EXPLAIN ANALYZE để so sánh số hàng ước tính với số hàng thực tế được trả về bởi mỗi thao tác.

Hãy xem một ví dụ, sử dụng lại cùng một dữ liệu:

 KẾ HOẠCH QUERY | -------------------------------------------- -------------------------------------------------- ------------- + Sắp xếp (chi phí =66,83..69,33 hàng =1000 chiều rộng =17) (thời gian thực tế =20,569..20,684 hàng =1000 vòng =1) | Khóa sắp xếp:tên người dùng | Phương pháp sắp xếp:nhanh chóng Bộ nhớ:102kB | -> Quét Seq trên người dùng (chi phí =0,00..17,00 hàng =1000 chiều rộng =17) (thời gian thực =0,048..0,596 hàng =1000 vòng =1) | Thời gian lập kế hoạch:0,171 ms | Thời gian thực hiện:20,793 ms |  

Chúng ta có thể thấy rằng tổng chi phí thực hiện vẫn là 69,33, với phần lớn là hoạt động Sắp xếp và 17,00 đến từ Quét tuần tự. Lưu ý rằng thời gian thực hiện truy vấn chỉ dưới 21 mili giây.

Quét tuần tự so với Quét chỉ mục

Bây giờ, hãy thêm một chỉ mục để cố gắng tránh loại tốn kém đó cho toàn bộ bảng:

 TẠO CHỈ SỐ people_username_idx TRÊN người dùng (tên người dùng); GIẢI THÍCH PHÂN TÍCH LỰA CHỌN * TỪ người dùng ĐẶT HÀNG THEO tên người dùng; KẾ HOẠCH QUERY | ----------------------- -------------------------------------------------- -------------------------------------------------- ------ + Quét chỉ mục bằng cách sử dụng people_username_idx trên người dùng (chi phí =0,28..28,27 hàng =1000 chiều rộng =17) (thời gian thực =0,052..1,494 hàng =1000 vòng =1) | Thời gian lập kế hoạch:0,186 mili giây | Thực hiện Thời gian:1,686 ms | 

Như bạn có thể thấy, trình lập kế hoạch truy vấn hiện đã chọn Quét chỉ mục, vì tổng chi phí của kế hoạch đó là 28,27 (thấp hơn 69,33). Có vẻ như quét chỉ mục hiệu quả hơn quét tuần tự, vì thời gian thực hiện truy vấn hiện chỉ dưới 2ms.

Giúp người lập kế hoạch ước tính chính xác hơn

Chúng tôi có thể giúp người lập kế hoạch ước tính chính xác hơn theo hai cách:

  1. Giúp nó thu thập số liệu thống kê tốt hơn
  2. Điều chỉnh các hằng số mà nó sử dụng để tính toán

Các số liệu thống kê có thể đặc biệt tồi tệ sau một thay đổi lớn đối với dữ liệu trong bảng. Do đó, khi tải nhiều dữ liệu vào một bảng, bạn có thể giúp Postgres out bằng cách chạy ANALYZE thủ công trên đó. Số liệu thống kê cũng không tồn tại qua một lần nâng cấp phiên bản lớn, vì vậy, đó là thời điểm quan trọng khác để thực hiện việc này.

Đương nhiên, các bảng cũng thay đổi theo thời gian, vì vậy việc điều chỉnh cài đặt autovacuum để đảm bảo nó chạy đủ thường xuyên cho khối lượng công việc của bạn có thể rất hữu ích.

Nếu bạn gặp khó khăn với ước tính sai cho một cột có phân phối lệch, bạn có thể được lợi từ việc tăng lượng thông tin mà Postgres thu thập bằng cách sử dụng ALTER TABLE SET STATISTICS hoặc thậm chí là default_statistics_target cho toàn bộ cơ sở dữ liệu.

Một nguyên nhân phổ biến khác của các ước tính sai là theo mặc định, Postgres sẽ cho rằng hai cột là độc lập. Bạn có thể khắc phục điều này bằng cách yêu cầu nó thu thập dữ liệu tương quan trên hai cột từ cùng một bảng thông qua thống kê mở rộng.

Ở mặt trước điều chỉnh liên tục, có rất nhiều thông số bạn có thể điều chỉnh để phù hợp với phần cứng của mình. Giả sử bạn đang chạy trên SSD, ít nhất bạn sẽ muốn điều chỉnh cài đặt random_page_cost của mình . Giá trị này mặc định là 4, đắt hơn gấp 4 lần so với seq_page_cost chúng tôi đã xem xét trước đó. Tỷ lệ này có ý nghĩa trên đĩa quay, nhưng trên SSD, nó có xu hướng phạt I / O ngẫu nhiên quá nhiều. Vì cài đặt như vậy gần 1 hoặc giữa 1 và 2, có thể có ý nghĩa hơn. Tại ScaleGrid, chúng tôi mặc định là 1.

Tôi có thể xóa chi phí khỏi các kế hoạch truy vấn không?

Vì nhiều lý do được đề cập ở trên, hầu hết mọi người để nguyên chi phí khi chạy EXPLAIN . Tuy nhiên, nếu muốn, bạn có thể tắt chúng bằng cách sử dụng COSTS tham số.

 GIẢI THÍCH (TẮT CHI PHÍ) CHỌN * TỪ người dùng GIỚI HẠN 1; KẾ HOẠCH QUERY | ----------------------- + Giới hạn | -> Quét Seq trên người dùng | 

Kết luận

Để giới hạn lại, chi phí trong các kế hoạch truy vấn là ước tính của Postgres cho khoảng thời gian mà một truy vấn SQL sẽ mất, trong một đơn vị tùy ý.

Nó chọn kế hoạch có tổng chi phí thấp nhất, dựa trên một số hằng số có thể định cấu hình và một số thống kê mà nó đã thu thập được.

Giúp nó ước tính những chi phí này chính xác hơn là rất quan trọng để giúp nó đưa ra những lựa chọn tốt và giữ cho các truy vấn của bạn hoạt động hiệu quả.

Bạn muốn tìm hiểu thêm về ScaleGrid?

Để tìm hiểu thêm về cách ScaleGrid có thể giúp bạn quản lý cơ sở dữ liệu của mình, hãy liên hệ với chúng tôi và chúng tôi có thể cho bạn thấy tất cả những gì DBaaS của chúng tôi cung cấp. Tìm hiểu thêm về cách ScaleGrid có thể cho phép bạn tập trung nhiều hơn vào việc phát triển sản phẩm của mình và ít hơn vào việc quản lý cơ sở dữ liệu.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tại sao chúng ta cần các nhà môi giới tin nhắn như RabbitMQ trên cơ sở dữ liệu như PostgreSQL?

  2. Gọi một thủ tục được lưu trữ trong một thủ tục được lưu trữ

  3. Tên cột PostgreSQL có phân biệt chữ hoa chữ thường không?

  4. Truy xuất tất cả các đặc quyền đối tượng cho vai trò cụ thể

  5. Khôi phục Pgbackrest và Khôi phục Delta