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

Hiểu hiệu suất truy vấn PostgreSQL

Tìm ra lý do tại sao một truy vấn hoạt động tốt trong quá trình phát triển và thử nghiệm lại tác động lên quá trình sản xuất đôi khi có thể là một thách thức. Đọc tiếp để tìm hiểu thêm về một số tính năng có thể cung cấp thông tin chi tiết về cách các truy vấn của bạn hoạt động trong quá trình sản xuất.

Các Truy vấn Hiện đang Chạy

Khi một máy khách kết nối máy chủ PostgreSQL, quá trình máy chủ Postgres chính (trước đây được gọi là postmaster ) tạo ra một quy trình mới (được gọi là backend ) để phục vụ các truy vấn của khách hàng. Do đó, mỗi phần phụ trợ đang chờ ứng dụng khách của nó gửi một truy vấn hoặc cố gắng thực thi một truy vấn.

Chế độ xem hệ thống pg_stat_activity hiển thị thông tin về mọi chương trình phụ trợ hiện đang chạy. Đặc biệt, nó hiển thị truy vấn mà chương trình phụ trợ hiện đang thực thi nếu đang hoạt động hoặc truy vấn cuối cùng mà nó thực thi nếu đang đợi khách gửi một truy vấn khác.

Đây là hai phần phụ trợ phục vụ các máy khách được kết nối với cơ sở dữ liệu testdb , với phần lớn họ chủ động thực hiện các truy vấn của mình:

testdb=# select usename,datname,state,query from pg_stat_activity where datname='testdb';
-[ RECORD 1 ]-----------------------------------------------------------------------------
usename | postgres
datname | testdb
state   | active
query   | SELECT pg_sleep(10);
-[ RECORD 2 ]-----------------------------------------------------------------------------
usename | postgres
datname | testdb
state   | active
query   | select usename,datname,state,query from pg_stat_activity where datname='testdb';

Đôi khi truy vấn có thể đang chờ khóa và điều này cũng hiển thị trongpg_stat_activity. Bạn có thể thấy INSERT đang chờ khóa quan hệ tại đây:

testdb=# select wait_event_type, wait_event, left(query, 60) from pg_stat_activity where datname='testdb';
-[ RECORD 1 ]---+-------------------------------------------------------------
wait_event_type | Client
wait_event      | ClientRead
left            | lock table t in access exclusive mode;
-[ RECORD 2 ]---+-------------------------------------------------------------
wait_event_type |
wait_event      |
left            | select wait_event_type, wait_event, left(query, 60) from pg_
-[ RECORD 3 ]---+-------------------------------------------------------------
wait_event_type | Lock
wait_event      | relation
left            | insert into t values (1);

Để biết thêm thông tin về pg_stat_activity, hãy xem tài liệu.

Mặc dù chế độ xem này hữu ích để hiểu những gì Postgres hiện đang làm, nó không cung cấp thông tin về thống kê thực thi truy vấn hoặc thông tin về các truy vấn đã hoàn thành thực thi.

Tất cả các truy vấn đều chạy trong quá khứ

Đối với điều đó, tiện ích mở rộng pg_stat_statements là vô giá. Các phần mở rộng này bao gồm trong bản phân phối PostgreSQL cốt lõi và cũng có sẵn trên các dịch vụ được quản lý như AWS RDS và GCP SQL.

pg_stat_statements (PSS) là một “phần mở rộng” trong các thuật ngữ PostgreSQL và cần được cài đặt trước:

  • Tham khảo tài liệu về bản phân phối Linux của bạn để xem liệu tiện ích mở rộng đã được cài đặt trước chưa hoặc liệu nó có yêu cầu cài đặt gói khác hay không. Ví dụ, trên Centos 7, bạn sẽ cần sudo yum cài đặt postgresql-Contrib .
  • Chỉnh sửa tệp cấu hình chính postgresql.conf (thường trong / etc , như /etc/postgresql/10/main/postgresql.conf trên Debian) và thay đổi giá trị của shared_preload_libraries thành “pg_stat_statements”. Đây là danh sách các giá trị được phân tách bằng dấu phẩy, vì vậy nếu đã có thứ gì đó ở đó, hãy thêm dấu phẩy và sau đó “pg_stat_statements”.
  • Đối với AWS RDS, bạn sẽ cần sửa đổi nhóm thông số đang hoạt động của mình và đặt giá trị.
  • Sau khi chỉnh sửa “shared_preload_libraries”, bạn cần khởi động lại daemonPostgreSQL. Thật không may là không có cách nào để giải quyết vấn đề này. Trên AWS RDS, bạn cần khởi động lại phiên bản RDS.
  • Sau khi khởi động lại, máy chủ PostgreSQL sẽ tải thư viện được chia sẻ và chúng tôi có thể cài đặt tiện ích mở rộng bằng cách chạy CREATE EXTENSIONpg_stat_statements . Bạn cần phải là một siêu người dùng để chạy lệnh này.
  • Bạn thực sự có thể cài đặt tiện ích mở rộng này trong bất kỳ cơ sở dữ liệu nào nhưng vẫn có thể xem các truy vấn trên tất cả các cơ sở dữ liệu.

Sau khi tiện ích mở rộng được cài đặt, bạn có thể truy vấn chế độ xem có tên pg_stat_statements để nhận thông tin về mọi truy vấn được thực thi kể từ khi tiện ích mở rộng được cài đặt.

Các con số, giống như thời gian cần thiết để thực hiện truy vấn, được tích lũy thành một tổng. Chỉ riêng thời gian thực hiện truy vấn, một số thống kê (trung bình, tối thiểu, tối đa, độ lệch chuẩn) được trình bày. Có thể xóa các giá trị này bằng cách sử dụng hàm pg_stat_statements_reset .

Đây là cách một hàng từ pg_stat_statements trông giống như:

testdb=# select * from pg_stat_statements where query like '%pg_sleep%' and dbid=42548;
-[ RECORD 1 ]-------+--------------------
userid              | 10
dbid                | 42548
queryid             | 2649515222348904837
query               | SELECT pg_sleep($1)
calls               | 1
total_time          | 10016.782625
min_time            | 10016.782625
max_time            | 10016.782625
mean_time           | 10016.782625
stddev_time         | 0
rows                | 1
shared_blks_hit     | 0
shared_blks_read    | 0
shared_blks_dirtied | 0
shared_blks_written | 0
local_blks_hit      | 0
local_blks_read     | 0
local_blks_dirtied  | 0
local_blks_written  | 0
temp_blks_read      | 0
temp_blks_written   | 0
blk_read_time       | 0
blk_write_time      | 0

Ngoài các tham số xác định (người dùng, cơ sở dữ liệu, truy vấn), bạn có thể tìm ra nhiều điều thú vị về truy vấn của mình:

  • Thông thường mất bao lâu để thực thi ( mean_time )
  • Trung bình nó trả về bao nhiêu hàng ( hàng / cuộc gọi )
  • Lượng dữ liệu được đọc từ bộ đệm chia sẻ bộ đệm và lượng dữ liệu từ đĩa ( shared_blks_read hiển thị tổng lượng dữ liệu mà truy vấn đã đọc, trong đó shared_blks_hit đến từ bộ nhớ cache)
  • Lượng dữ liệu phải được ghi vào đĩa một cách đồng bộ do áp lực của bộ nhớ cache ( shared_blks_written )
  • Lượng dữ liệu được ghi, như số lượng khối được chạm vào ( shared_blks_dirtied )
  • Lượng thời gian đĩa đọc và ghi ( blk_ {read, write} _time )
  • Các tệp tạm thời được ghi vào và đọc từ ( temp_blks_ {read, write} )
  • Các bảng tạm thời được ghi vào và đọc từ ( local_ * )

Thời gian đọc và ghi đĩa chỉ khả dụng nếu tham số cấu hình track_io_timing Được bật. Theo mặc định, nó không phải là. Trên hầu hết các hệ thống Linux hiện đại, bạn có thể bật thông số này lên. Đọc thêm.

Bạn nên chụp nhanh pg_stat_statements dữ liệu liên tục theo khoảng thời gian không đều để xem các thông số này có xu hướng như thế nào trên cơ sở mỗi truy vấn. dữ liệu dưới dạng JSON để tự động hóa dễ dàng hơn.

Truy vấn Chạy trong Phạm vi Thời gian

Khi bạn đã có một hệ thống như vậy, bạn sẽ dễ dàng theo dõi các truy vấn được thực hiện trong một khung thời gian nhất định. Điều này giúp bạn dễ dàng gỡ lỗi các vấn đề như tại sao công việc hàng loạt trong một đêm diễn ra lâu hơn dự kiến.

Bằng cách trừ các bộ đếm giữa hai dấu thời gian nhất định, bạn có thể tìm ra hầu hết các số như trước đây, ngoại trừ độ lệch chuẩn tối thiểu, tối đa và độ lệch chuẩn.>

Ghi nhật ký Truy vấn Chậm

Một cách khác để nhanh chóng xác định các truy vấn mất nhiều thời gian hơn dự kiến ​​là bật tính năng ghi nhật ký các câu lệnh. Bạn có thể chỉ định thời lượng ngưỡng và nếu truy vấn mất nhiều thời gian hơn thời gian này để hoàn thành, nó sẽ được ghi lại. (Trong tệp nhật ký PostgreSQL thông thường, không có tệp nhật ký riêng cho các truy vấn chậm.)

Để bật tính năng này, hãy chỉnh sửa cấu hình như sau:

log_min_duration_statement = 1000 # in milliseconds

và tải lại Postgres. Bạn cũng có thể sử dụng ALTER SYSTEM :

ALTER SYSTEM SET log_min_duration_statement = 1000; -- in milliseconds

Với điều này, bất kỳ câu lệnh nào (bao gồm cả những câu lệnh không phải DML) mất hơn một giây để hoàn thành sẽ được ghi lại:

2019-12-02 16:57:05.727 UTC [8040] postgres@testdb LOG:  duration: 10017.862 ms  statement: SELECT pg_sleep(10);

Thời gian thực tế được thực hiện bởi truy vấn, cũng như toàn bộ văn bản SQL, được ghi lại.

Nếu bạn có một hệ thống giám sát nhật ký và có thể theo dõi số lượng truy vấn chậm mỗi giờ / mỗi ngày, nó có thể là một chỉ báo tốt về hiệu suất ứng dụng.

Kế hoạch Thực thi Truy vấn

Khi bạn đã xác định được một truy vấn mà bạn cảm thấy sẽ chạy nhanh hơn, bước tiếp theo là xem xét kế hoạch truy vấn của nó. Thông thường, bạn cần kế hoạch truy vấn thực tế từ máy chủ sản xuất để làm việc với. Nếu bạn có thể chạyEXPLAIN trên các máy chủ sản xuất tốt như vậy, thì bạn cần phải dựa vào auto_explain .

auto_explain là một phần mở rộng PostgreSQL cốt lõi khác, đã được cài đặt hoặc có sẵn dưới dạng gói “đóng góp” cho bản phân phối của bạn. Nó cũng có sẵn trên AWSRDS. auto_explain cài đặt đơn giản hơn một chút so với pg_stat_statements :

  • Chỉnh sửa cấu hình postgres (hoặc nhóm thông số RDS) shared_preload_libraries để bao gồm auto_explain .
  • Tuy nhiên, bạn không phải khởi động lại Postgres, thay vào đó bạn có thể chỉ chạy: LOAD 'auto_explain'; .
  • Bạn sẽ muốn định cấu hình cài đặt của nó, ít nhất là cài đặt này:
    • auto_explain.log_min_duration =1000 # giây

Về cơ bản, bất cứ khi nào truy vấn mất nhiều thời gian hơn auto_explain.log_min_duration số giây để hoàn thành, auto_explain ghi lại truy vấn và đó là kế hoạch thực thi truy vấn trong tệp nhật ký, như sau:

2019-12-04 09:23:05.130 UTC [12823] postgres@testdb LOG:  duration: 11025.765 ms  plan:
        Query Text: select pg_sleep(11);
        Result  (cost=0.00..0.01 rows=1 width=4) (actual time=11025.716..11025.718 rows=1 loops=1)
          Output: pg_sleep('11'::double precision)

Nó cũng có thể ghi lại kế hoạch ở định dạng JSON, nếu bạn có tập lệnh có thể xử lý nó:

2019-12-02 17:30:53.676 UTC [8040] postgres@testdb LOG:  duration: 10000.230 ms  plan:
        {
          "Query Text": "SELECT pg_sleep(10);",
          "Plan": {
            "Node Type": "Result",
            "Parallel Aware": false,
            "Startup Cost": 0.00,
            "Total Cost": 0.01,
            "Plan Rows": 1,
            "Plan Width": 4,
            "Actual Startup Time": 10000.205,
            "Actual Total Time": 10000.206,
            "Actual Rows": 1,
            "Actual Loops": 1,
            "Output": ["pg_sleep('10'::double precision)"],
            "Shared Hit Blocks": 0,
            "Shared Read Blocks": 0,
            "Shared Dirtied Blocks": 0,
            "Shared Written Blocks": 0,
            "Local Hit Blocks": 0,
            "Local Read Blocks": 0,
            "Local Dirtied Blocks": 0,
            "Local Written Blocks": 0,
            "Temp Read Blocks": 0,
            "Temp Written Blocks": 0,
            "I/O Read Time": 0.000,
            "I/O Write Time": 0.000
          },
          "Triggers": [
          ]
        }

Trong Postgres, không có cách nào khác ngoài auto_explain để xem sơ đồ thực thi của một truy vấn đã được thực thi, điều này làm cho auto_explain trở thành một món đồ quan trọng trong hộp công cụ của bạn.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Các tính năng của phương pháp sao lưu PostgreSQL trong AWS S3

  2. @JoinColumn là gì và nó được sử dụng như thế nào trong Hibernate

  3. Làm cách nào để làm cho Java và Postgres enums hoạt động cùng nhau để cập nhật?

  4. Heroku Postgres:Quá nhiều mối quan hệ. Tôi làm cách nào để loại bỏ các kết nối này?

  5. PGTune Alternatives - ClusterControl PostgreSQL Configuration