本文介紹RDS PostgreSQL的一些開發運維建議,幫助您有效提升數據庫使用的規范性和穩定性,保持高性能。
客戶端連接池
使用綁定變量(PreparedStatement),消除數據庫SQL硬解析CPU消耗,對性能提升巨大。
減少idle connection數量。可以降低RDS PostgreSQL連接內存占用,并提升
GetSnapshotData()
效率,提升性能。使用應用連接池,避免短連接損耗和性能下降。如果應用沒有連接池,建議在應用層和數據庫之間架設連接池,例如使用PgBouncer或者Pgpool-II作為連接池。
應用連接池參數的配置建議:
minimumIdle=1
:控制連接池空閑連接的最小數量,減少idle connection。說明當前大多數連接池已取消了maxIdle參數,如果有,maxIdle參數設置為1。
maxLifetime
:建議設置為60分鐘,用來設置一個connection在連接池中的最大存活時間。可以極大降低連接Relcache內存導致OOM的概率。maximumPoolSize=15
:單個連接池實例允許的最大連接數,15已經滿足絕大多數應用需求。如果連接池客戶端個數較少,負載集中,可以適當增大這些客戶端的maximumPoolSize。
說明常見應用連接池參數的配置建議如下:
HikariCP(Java,推薦的連接池):
minimumIdle=1, maximumPoolSize=15, idleTimeout=600000 (10 minutes), maxLifetime=3600000 (60 minutes)
GORM(golang,推薦的連接池):
sqlDB.SetMaxIdleConns(1), sqlDB.SetMaxOpenConns(15), sqlDB.SetConnMaxLifetime(time.Hour)
Druid(Java):
initialSize=1, minIdle=1, maxIdle=1, maxActive=15, testOnBorrow=false, testOnReturn=false, testWhileIdle=true,minEvictableIdleTimeMillis=600000 (10 minutes), maxEvictableIdleTimeMillis=900000 (15 minutes), timeBetweenEvictionRunsMillis=60000 (1 minutes), maxWait=6000 (6 seconds).
上述配置不涉及PreparedStatement配置,PreparedStatement需要另外配置。
性能與穩定性
在RDS PostgreSQL中,單個數據庫(DB)對應底層文件系統中的一個文件夾,數據庫中的表、分區、索引對應文件夾中的文件,如果數據庫對應文件夾中的文件數量超過2000萬,將可能出現磁盤空間滿的報錯。建議適當拆分數據庫或合并表文件。
新建索引,對于在線業務,推薦使用CREATE INDEX CONCURRENTLY方式創建索引,不堵塞其他會話對被創建索引表的DML(INSERT、UPDATE或DELETE)操作。創建方法請參見CONCURRENTLY方式創建索引。
重建索引,對PostgreSQL 12及以上大版本,使用REINDEX CONCURRENTLY。PostgreSQL 11及下大版本,使用CONCURRENTLY創建新索引成功后,再刪除老索引。
避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。特別是ON COMMIT DROP,務必慎用。通常臨時表功能,可以使用WITH語句替代。
PostgreSQL13在分區表、HashAggregate(group by)、并行查詢等有較大的優化,建議升級PostgreSQL大版本。具體請參見RDS PostgreSQL升級數據庫大版本。
游標使用后及時關閉。
使用TRUNCATE代替DELETE全表,提升性能。
PostgreSQL支持DDL事務,支持回滾DDL,建議將DDL封裝在事務中執行,必要時可以回滾,但是需要注意事務的長度,避免長時間堵塞DDL對象的讀操作。
如果有大批量的數據入庫,建議使用copy語法,或者
INSERT INTO table VALUES (),(),...();
的方式,提高寫入速度。
實例小版本建議
監控告警
強烈建議開啟RDS PostgreSQL云監控模板的告警項,參見管理報警。
您可以根據業務情況自行設置內存使用率告警閾值,建議設置在85%到95%之間。
問題排查
RDS PostgreSQL慢SQL問題排查:請參見慢SQL統計和分析方法(EXPLAIN)。
查找最耗費資源的SQL(Top SQL):請參見查找最耗費資源的 SQL(Top SQL)。
設計
權限
權限管理,以schema/role為單位分配權限,創建readwrite/readonly賬號,遵循最小權限原則,請參見RDS PostgreSQL權限管理最佳實踐。
若使用應?層讀寫分離,readonly客戶端建議使?readonly賬號,最小權限原則,避免權限誤用。
表
表結構中字段定義的數據類型建議與應用程序中的定義保持一致,表之間字段校對規則一致,避免報錯或無法使用索引的情況發生。
對于存在定期歷史數據刪除需求的業務,建議數據表按時間分區,按時間月或年區分,刪除時使用
DROP
或者TRUNCATE
操作對應的子表,不建議使用DELETE
操作。對于頻繁更新的表,建議在建表時指定表的
FILLFACTOR=85
,每頁預留15%的空間用于HOT更新。CREATE TABLE test123(id int, info text) WITH(FILLFACTOR=85);
臨時表建議以
tmp_
開頭,子表建議根據業務場景以規則結尾,例如按年分區的主表如果為tbl,則子表為tbl_2016、tbl_2017等。
索引
B-Tree索引字段至多2000字節,如果存在超過2000字節的字段需要新建索引,建議使用函數索引(例如哈希值索引)或分詞索引。
對于線性順序存儲的數據(如流式數據、時間字段或自增字段),通常查詢時使用范圍查詢,建議使用
BRIN
索引,減少索引的大小,加快數據插入速度。CREATE INDEX idx ON tbl using BRIN(id);
建議避免全表掃描(大數據量掃描的數據分析除外),PostgreSQL支持幾乎所有數據類型的索引。
索引接口包括:B-Tree、Hash、GIN、GiST、SP-GiST、BRIN、RUM(擴展接口)、Bloom(擴展接口)、PASE(擴展接口)。
主鍵索引建議以
pk_
開頭, 唯一索引建議以uk_
開頭,普通索引建議以idx_
開頭。
數據類型及字符集
建議選擇合適的數據類型,目標數據為數字時不建議使用字符串,目標數據可以存為樹類型時不建議使用字符串。
使用合理的數據類型,可以提高數據的查詢效率。
PostgreSQL支持的數據類型如下:精確的數字類型、浮點、貨幣、字符串、字符、字節流、日期、時間、布爾、枚舉、幾何、網絡地址、比特流、文本、UUID、XML、JSON、數組、復合類型、范圍類型、對象、行號、大對象、ltree樹結構類型、cube多維類型、earth地球類型、hstore類型、pg_trgm相似類型、PostGIS(點、線段、面、路徑、經緯度、raster、拓撲等)、HyperLogLog(近似估值統計分析)。
字符串排序規則LC_COLLATE推薦使用 'C',而非 UTF8。LC_COLLATE=UTF8 性能相對差一些,并且索引需要明確指定UTF8 pattern ops,才能支持LIKE查詢。
存儲過程
如果業務邏輯冗長,建議減少數據庫和程序之間的交互次數,使用數據庫存儲過程(如 PL/pgSQL)或內置函數。PostgreSQL內置的PL/pgSQL函數語言提供處理復雜業務邏輯的功能。PostgreSQL還內置了分析函數、聚合函數、窗口函數、普通類型函數、復雜類型函數、數學函數和幾何函數等多種函數。
數據查詢
不建議使用
COUNT(列名)
或COUNT(常量)
來替代COUNT(*)
,COUNT(*)
是SQL92定義的標準統計行數的語法,會統計NULL值(真實行數),而COUNT(列名)
不會統計。使用
COUNT(多列列名)
時,多列列名必須使用括號,例如COUNT( (col1,col2,col3) )
。注意使用COUNT(多列列名)
時,所有NULL行都會被計數,所以效果與COUNT(*)
一致。不建議使用
SELECT * FROM t
,用具體的字段列表代替*
,避免返回用不到的字段。除ETL(Extract-Transform-Load)程序外,建議避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。
對于需要范圍查詢的場景,建議使用范圍類型以及GiST索引,提高范圍檢索的查詢性能。
如果應用經常訪問較大結果集的數據(例如100條),建議將數據聚合成1條,例如經常要按ID訪問此ID的數據,建議定期按ID聚合數據,查詢時返回的記錄數越少響應越快。
管理
建議開啟SQL洞察和審計,該功能支持查詢并導出SQL語句執行歷史及其對應的各種信息(數據庫、狀態、執行時間等),對SQL進行健康情況診斷、性能問題排查、業務流量分析等。更多信息,請參見SQL洞察和審計。
如果您需要監控并記錄阿里云賬號的活動,包括通過阿里云控制臺、OpenAPI、開發者工具對云上產品和服務的訪問和使用行為,建議使用操作審計功能。您還可以將這些行為事件下載或保存到日志服務或OSS存儲空間,然后進行行為分析、安全分析、資源變更行為追蹤和行為合規性審計等操作。更多信息,請參見什么是操作審計。
DDL操作之前務必要經過評審,并且選擇在低峰期執行。
刪除和修改記錄時,為避免誤刪除,建議先使用
SELECT
確認后,再提交執行。如果業務邏輯上確定只更改1行,則添加LIMIT 1
。DDL操作(以及類似的可能獲取鎖的操作,例如
VACUUM FULL
、CREATE INDEX
等)建議設置鎖等待,用于防止堵塞所有與該DDL鎖對象相關的查詢。begin; SET local lock_timeout = '10s'; -- DDL query; end;
EXPLAIN (ANALYZE) 語句的工作方式類似于EXPLAIN,主要區別在于前者會實際執行SQL。如果SQL涉及數據變更,即DML SQL(UPDATE、INSERT或DELETE),務必在事務中執行EXPLAIN (ANALYZE),查看完成后再進行回滾。
begin; EXPLAIN (ANALYZE) <DML(UPDATE/INSERT/DELETE) SQL>; rollback;
大批量刪除和更新數據時,建議分批次操作,不建議在一個事務中完成,以免一次產生較多垃圾。