PostgreSQL學習手冊(數據庫維護) 轉

原文:?PostgreSQL學習手冊(數據庫維護)

?

?一、恢復磁盤空間:


?? ?在PostgreSQL中,使用delete和update語句刪除或更新的數據行并沒有被實際刪除,而只是在舊版本數據行的物理地址上將該行的狀態置為已刪除或已過期。因此當數據表中的數據變化極為頻繁時,那么在一段時間之后該表所占用的空間將會變得很大,然而數據量卻可能變化不大。要解決該問題,需要定期對數據變化頻繁的數據表執行VACUUM操作。
?? ?VACUUM命令存在兩種形式,VACUUMVACUUM FULL,它們之間的區別見如下表格:

?無VACUUMVACUUMVACUUM FULL
刪除大量數據之后只是將刪除數據的狀態置為已刪除,該空間不能記錄被重新使用。如果刪除的記錄位于表的末端,其所占用的空間將會被物理釋放并歸還操作系統。如果不是末端數據,該命令會將指定表或索引中被刪除數據所占用空間重新置為可用狀態,那么在今后有新數據插入時,將優先使用該空間,直到所有被重用的空間用完時,再考慮使用新增的磁盤頁面。不論被刪除的數據是否處于數據表的末端,這些數據所占用的空間都將被物理的釋放并歸還于操作系統。之后再有新數據插入時,將分配新的磁盤頁面以供使用。
執行效率?由于只是狀態置為操作,因此效率較高。在當前版本的PostgreSQL(v9.1)中,該命令會為指定的表或索引重新生成一個數據文件,并將原有文件中可用的數據導入到新文件中,之后再刪除原來的數據文件。因此在導入過程中,要求當前磁盤有更多的空間可用于此操作。由此可見,該命令的執行效率相對較低。
被刪除的數據所占用的物理空間是否被重新規劃給操作系統。不會不會
在執行VACUUM命令時,是否可以并發執行針對該表的其他操作。?由于該操作是共享鎖,因此可以與其他操作并行進行。由于該操作需要在指定的表上應用排它鎖,因此在執行該操作期間,任何基于該表的操作都將被掛起,知道該操作完成。
推薦使用方式在進行數據清空是,可以使用truncate操作,因為該操作將會物理的清空數據表,并將其所占用的空間直接歸還于操作系統。為了保證數據表的磁盤頁面數量能夠保持在一個相對穩定值,可以定期執行該操作,如每天或每周中數據操作相對較少的時段。考慮到該操作的開銷,以及對其他錯誤的排斥,推薦的方式是,定期監控數據量變化較大的表,只有確認其磁盤頁面占有量接近臨界值時,才考慮執行一次該操作。即便如此,也需要注意盡量選擇數據操作較少的時段來完成該操作。
執行后其它操作的效率對于查詢而言,由于存在大量的磁盤頁面碎片,因此效率會逐步降低。相比于不執行任何VACUUM操作,其效率更高,但是插入的效率會有所降低。在執行完該操作后,所有基于該表的操作效率都會得到極大的提升。

?

二、更新規劃器統計:

?? ?PostgreSQL查詢規劃器在選擇最優路徑時,需要參照相關數據表的統計信息用以為查詢生成最合理的規劃。這些統計是通過ANALYZE命令獲得的,你可以直接調用該命令,或者把它當做VACUUM命令里的一個可選步驟來調用,如VACUUM ANAYLYZE?table_name,該命令將會先執行VACUUM再執行ANALYZE。與回收空間(VACUUM)一樣,對數據更新頻繁的表保持一定頻度的ANALYZE,從而使該表的統計信息始終處于相對較新的狀態,這樣對于基于該表的查詢優化將是極為有利的。然而對于更新并不頻繁的數據表,則不需要執行該操作。
?? ?我們可以為特定的表,甚至是表中特定的字段運行ANALYZE命令,這樣我們就可以根據實際情況,只對更新比較頻繁的部分信息執行ANALYZE操作,這樣不僅可以節省統計信息所占用的空間,也可以提高本次ANALYZE操作的執行效率。這里需要額外說明的是,ANALYZE是一項相當快的操作,即使是在數據量較大的表上也是如此,因為它使用了統計學上的隨機采樣的方法進行行采樣,而不是把每一行數據都讀取進來并進行分析。因此,可以考慮定期對整個數據庫執行該命令。
?? ?事實上,我們甚至可以通過下面的命令來調整指定字段的抽樣率,如:
?? ?ALTER TABLE?testtable?ALTER COLUMN?test_col?SET STATISTICS?200
?? ?注意:該值的取值范圍是0--1000,其中值越低采樣比例就越低,分析結果的準確性也就越低,但是ANALYZE命令執行的速度卻更快。如果將該值設置為-1,那么該字段的采樣比率將恢復到系統當前默認的采樣值,我們可以通過下面的命令獲取當前系統的缺省采樣值。
?? ?postgres=# show?default_statistics_target;
?? ? default_statistics_target
?? ?---------------------------
?? ? 100
?? ?(1 row)
?? ?從上面的結果可以看出,該數據庫的缺省采樣值為100(10%)。


三、VACUUM和ANALYZE的示例:
?? ?

??? #1. 創建測試數據表。
????postgres=# CREATE TABLE testtable (i integer);
??? CREATE TABLE
????#2. 為測試表創建索引。
????postgres=# CREATE INDEX testtable_idx ON testtable(i);
??? CREATE INDEX
????#3. 創建批量插入測試數據的函數。
??? postgres=# CREATE OR REPLACE FUNCTION test_insert() returns integer AS $$
??? DECLARE
??? ??? min integer;
??? ??? max integer;
??? BEGIN
??? ??? SELECT COUNT(*) INTO min from testtable;
??? ??? max := min + 10000;
??? ??? FOR i IN min..max LOOP
??? ??????? INSERT INTO testtable VALUES(i);
??? ??? END LOOP;
??? ??? RETURN 0;
??? END;
??? $$ LANGUAGE plpgsql;
??? CREATE FUNCTION
????#4. 批量插入數據到測試表(執行四次)
????postgres=# SELECT test_insert();
??? ?test_insert
??? -------------
??? ?????????? 0
??? (1 row)
????#5. 確認四次批量插入都成功。
????postgres=# SELECT COUNT(*) FROM testtable;
??? ?count
??? -------
??? ?40004
??? (1 row)
????#6. 分析測試表,以便有關該表的統計信息被更新到PostgreSQL的系統表。
????postgres=# ANALYZE testtable;
??? ANALYZE
????#7. 查看測試表和索引當前占用的頁面數量(通常每個頁面為8k)。
????postgres=# SELECT relname,relfilenode, relpages FROM pg_class WHERE relname = 'testtable' or relname = 'testtable_idx';
??? ??? relname?? ? ? | relfilenode??? | relpages
??? ---------------+-------------+----------
??? ?testtable??????? |?????? 17601 ? |????? 157
??? ?testtable_idx? |?????? 17604?? |?????? 90
????#8. 批量刪除數據。
??? postgres=# DELETE FROM testtable WHERE i < 30000;
??? DELETE 30003
??? #9. 執行vacuum和analyze,以便更新系統表,同時為該表和索引記錄高水標記。
??? #10. 這里需要額外說明的是,上面刪除的數據均位于數據表的前部,如果刪除的是末尾部分,
??? #????? 如where i > 10000,那么在執行VACUUM ANALYZE的時候,數據表將會被物理的縮小。
??? postgres=# VACUUM ANALYZE testtable;
??? ANALYZE
????#11. 查看測試表和索引在刪除后,再通過VACUUM ANALYZE更新系統統計信息后的結果(保持不變)。
??? postgres=# SELECT relname,relfilenode, relpages FROM pg_class WHERE relname = 'testtable' or relname = 'testtable_idx';
??? ??? relname? ? ? | relfilenode???? | relpages
??? ---------------+-------------+----------
??? ?testtable??????? |?????? 17601?? |????? 157
??? ?testtable_idx? |?????? 17604?? |?????? 90
??? (2 rows)
????#12. 再重新批量插入兩次,之后在分析該表以更新其統計信息。
??? postgres=# SELECT test_insert(); --執行兩次。
??? ?test_insert
??? -------------
??? ?????????? 0
??? (1 row)
??? postgres=# ANALYZE testtable;
??? ANALYZE
??? #13. 此時可以看到數據表中的頁面數量仍然為之前的高水標記數量,索引頁面數量的增加
??? #?? ?? 是和其內部實現方式有關,但是在后面的插入中,索引所占的頁面數量就不會繼續增加。
??? postgres=# SELECT relname,relfilenode, relpages FROM pg_class WHERE relname = 'testtable' or relname = 'testtable_idx';
??? ??? relname?????? | relfilenode??? | relpages
??? ---------------+-------------+----------
??? ?testtable??? ? ? |?????? 17601?? |????? 157
??? ?testtable_idx? |?????? 17604 ? |????? 173
??? (2 rows)
??? postgres=# SELECT test_insert();
??? ?test_insert
??? -------------
??? ?????????? 0
??? (1 row)
??? postgres=# ANALYZE testtable;
??? ANALYZE
????#14. 可以看到索引的頁面數量確實沒有繼續增加。
??? postgres=# SELECT relname,relfilenode, relpages FROM pg_class WHERE relname = 'testtable' or relname = 'testtable_idx';
??? ??? relname????? | relfilenode??? | relpages
??? ---------------+-------------+----------
??? ?testtable??? ? ? |?????? 17601?? |????? 157
??? ?testtable_idx? |?????? 17604?? |????? 173
??? (2 rows)
????#15. 重新批量刪除數據。
??? postgres=# DELETE FROM testtable WHERE i < 30000;
??? DELETE 19996
??? #16. 從后面的查詢可以看出,在執行VACUUM FULL命令之后,測試表和索引所占用的頁面數量
??? #????? 確實降低了,說明它們占用的物理空間已經縮小了。
??? postgres=# VACUUM FULL testtable;
??? VACUUM
??? postgres=# SELECT relname,relfilenode, relpages FROM pg_class WHERE relname = 'testtable' or relname = 'testtable_idx';
??? ??? relname?? ?? | relfilenode???? | relpages
??? ---------------+-------------+----------
??? ?testtable??? ? ? |?????? 17602 ? |????? 118
??? ?testtable_idx? |?????? 17605 ? |?????? 68
??? (2 rows)

四、定期重建索引:

?? ?在PostgreSQL中,為數據更新頻繁的數據表定期重建索引(REINDEX INDEX)是非常有必要的。對于B-Tree索引,只有那些已經完全清空的索引頁才會得到重復使用,對于那些僅部分空間可用的索引頁將不會得到重用,如果一個頁面中大多數索引鍵值都被刪除,只留下很少的一部分,那么該頁將不會被釋放并重用。在這種極端的情況下,由于每個索引頁面的利用率極低,一旦數據量顯著增加,將會導致索引文件變得極為龐大,不僅降低了查詢效率,而且還存在整個磁盤空間被完全填滿的危險。
?? ?對于重建后的索引還存在另外一個性能上的優勢,因為在新建立的索引上,邏輯上相互連接的頁面在物理上往往也是連在一起的,這樣可以提高磁盤頁面被連續讀取的幾率,從而提高整個操作的IO效率。見如下示例:
????#1. 此時已經在該表中插入了大約6萬條數據,下面的SQL語句將查詢該索引所占用的磁盤空間。????
????postgres=# SELECT relname, pg_relation_size(oid)/1024 || 'K' AS size FROM pg_class WHERE relkind='i' AND relname = 'testtable_idx';
?? ??? ?relname?? ? | size
?? ?----------------+------
?? ? testtable_idx | 1240K
?? ?(1 row)
?? ?#2. 刪除數據表中大多數的數據。
?? ?postgres=# DELETE FROM testtable WHERE i > 20000;
?? ?DELETE 50006
?? ?#3. 分析一個該表,以便于后面的SQL語句繼續查看該索引占用的空間。
?? ?postgres=# ANALYZE testtable;
?? ?ANALYZE
?? ?#4. 從該查詢結果可以看出,該索引所占用的空間并未減少,而是和之前的完全一樣。
?? ?postgres=# SELECT pg_relation_size('testtable_idx')/1024 || 'K' AS size;
?? ? size
?? ?------
?? ? 1240K
?? ?(1 row)
????#5. 重建索引。
?? ?postgres=# REINDEX INDEX testtable_idx;
?? ?REINDEX
?? ?#6. 查看重建后的索引實際占用的空間,從結果中可以看出索引的尺寸已經減少。
?? ?postgres=# SELECT pg_relation_size('testtable_idx')/1024 || 'K' AS size;
?? ? size
?? ?------
?? ? 368K
?? ?(1 row)
?? ?#7. 最后一點需要記住的是,在索引重建后一定要分析數據表。
?? ?postgres=# ANALYZE testtable;
?? ?ANALYZE

?五、觀察磁盤使用情況:

?? ?1. 查看數據表所占用的磁盤頁面數量。
?? ?#relpages只能被VACUUM、ANALYZE和幾個DDL命令更新,如CREATE INDEX。通常一個頁面的長度為8K字節。
?? ?postgres=# SELECT relfilenode, relpages FROM pg_class WHERE relname = 'testtable';
?? ? relfilenode | relpages
?? ?-------------+----------
?? ??????? 16412 |?????? 79
?? ?(1 row)
?? ?
?? ?2. 查看指定數據表的索引名稱和索引占用的磁盤頁面數量。
?? ?postgres=# SELECT c2.relname, c2.relpages FROM pg_class c, pg_class c2, pg_index i
?? ???? WHERE c.relname = 'testtable' AND c.oid = i.indrelid AND c2.oid = i.indexrelid
?? ???? ORDER BY c2.relname;
?? ???? relname??? | relpages
?? ?---------------+----------
?? ? testtable_idx |?????? 46
?? ?(1 row)

轉載于:https://www.cnblogs.com/kevinge/archive/2012/05/23/2514260.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/379689.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/379689.shtml
英文地址,請注明出處:http://en.pswp.cn/news/379689.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

++i與i++的根本性區別(兩個代碼對比搞定)

首先來看i 代碼如下&#xff1a; #include <stdio.h> #include <stdlib.h> int main() {int i0;int ai;printf("%d\n",a);printf("%d\n\n\n",i);return 0; }輸出結果如下&#xff1a; 解釋&#xff1a;i其實是兩行代碼的簡寫形式&#xff0c…

國企和外企的比較

由于本人在外企&#xff0c;而很多朋友在國企&#xff0c;因此我個人的說法應該還是有一定的權威性。 首先&#xff0c;國企和外企不能一概而論。正如任何事物都有三六九等&#xff0c;這個&#xff0c;只能在同等級別上進行比較。 國企分類&#xff1a; 一等國企&#xff1…

Python | 使用matplotlib.pyplot創建線圖

Problem statement: Write a program in python (using matplotlib.pyplot) to create a line plot. 問題陳述&#xff1a;用python編寫程序(使用matplotlib.pyplot)以創建線圖。 Program: 程序&#xff1a; import matplotlib.pyplot as pltx [1,2,3,4,5,6,7,8,9,10]y [3,…

QI(接口查詢)

接觸AE一段時間了&#xff0c;總的來說收獲不少&#xff0c;今天仔細分析了一下AE開發中經常會用到的QI即接口查詢&#xff0c;有了自己的一些理解。 COM類至少有一個接口。事實上一般它們有好幾個接口。即一個類經常會實現多個接口&#xff08;一個類無法繼承多個類&#xff0…

linux內核設計與實現---從內核出發

獲取、編譯、安裝內核1 獲取內核源碼安裝內核源代碼何處安裝源碼使用補丁2 內核源碼樹3 編譯內核減少編譯的垃圾信息衍生多個編譯作業安裝內核啟用指定內核作為引導4 內核開發的特點沒有libc庫頭文件沒有內存保護機制容積小而固定的棧1 獲取內核源碼 在linux內核官方網站http:…

MySQL在DOS下的基本命令操作

啟動net start mysql 重置root密碼 方法一:在my.ini的[mysqld]字段加入&#xff1a; skip-grant-tables 重啟mysql服務&#xff0c;這時的mysql不需要密碼即可登錄數據庫然后進入mysql mysql>use mysql;mysql>更新 user set passwordpassword(新密碼) WHERE Userroot; …

strlen的神奇實現

https://blog.delphij.net/2012/04/freebsd-strlen3.html 與 Pascal 等語言不同&#xff0c;C 的字符串并不保存串的長度&#xff0c;而是在字符串末尾以 nul 字符&#xff08;\0&#xff09;來表示字符串結束。這個設計決策是上世紀 60 年代作出的&#xff0c;有都市傳說是為了…

python求和_Python程序查找特殊求和系列的解決方案

python求和We are going to design a special sum series function which has following characteristics: 我們將設計一個特殊的求和系列函數&#xff0c;該函數具有以下特征&#xff1a; f(0) 0f(1) 1f(2) 1f(3) 0f(x) f(x-1) f(x-3)Python solution of the above sum…

linux內核設計與實現---進程管理

進程管理1 進程描述符及任務結構分配進程描述符進程描述符的存放進程狀態設置當前進程狀態進程上下文進程家族樹2 進程創建寫時拷貝fork()vfork()3 線程在Linux中的實現內核線程4 進程終結刪除進程描述符孤兒進程造成的進退微谷5 小結進程的另一個名字叫做任務&#xff08;task…

JS錯誤代碼解釋大全+VBS錯誤代碼解釋大全

JScript 運行時錯誤 JScript 運行時錯誤是指當 JScript 腳本試圖執行一個系統不能運行的動作時導致的錯誤。當正在運行腳本、計算變量表達式、或者正在動態分配內存時出現 JScript 運行時錯誤時。 錯誤號 描述 5029 數組長度必須為一有限正整數 5030 必須賦給數組長度一個有…

生日蠟燭(藍橋杯)

某君從某年開始每年都舉辦一次生日party&#xff0c;并且每次都要吹熄與年齡相同根數的蠟燭。 現在算起來&#xff0c;他一共吹熄了236根蠟燭。 請問&#xff0c;他從多少歲開始過生日party的&#xff1f; 請填寫他開始過生日party的年齡數。 注意&#xff1a;你提交的應該是…

python日歷模塊_Python日歷模塊| firstweekday()方法與示例

python日歷模塊Python calendar.firstweekday()方法 (Python calendar.firstweekday() Method) firstweekday() method is an inbuilt method of the calendar module in Python. It works on simple text calendars and returns the current setting for the weekday to start…

php 處理 mysql to json, 前臺js處理

public function GetJson(){$query"select * from table";$result mysql_query($query);$rows array();while($row mysql_fetch_array($result)){$rows [] $row;}echo json_encode($rows); } js處理 $.get( "./bll.php", option,function(data ) {var j…

Linux內核設計與實現---進程調度

進程調度1 策略I/O消耗型和處理器消耗型的進程進程優先級時間片進程搶占2 Linux調度算法可執行隊列優先級數組重新計算時間片schedule()計算優先級和時間片睡眠和喚醒負載平衡程序3 搶占和上下文切換用戶搶占內核搶占4 實時5 與調度相關的系統調用與調度策略和優先級相關的系統…

ServletContext(核心內容)

什么是ServletContext對象 ServletContext代表是一個web應用的環境&#xff08;上下文&#xff09;對象&#xff0c;ServletContext對象 內部封裝是該web應用的信息&#xff0c;ServletContext對象一個web應用只有一個 一個web應用有多個servlet對象 ServletContext對象的生…

【轉載】[TC]飛船動畫例子--《C高級實用程序設計》

【聲明和備注】本例子屬于轉載來源于《C高級實用程序設計》&#xff08;王士元&#xff0c;清華大學出版社&#xff09;第11章&#xff0c;菜單設計與動畫技術&#xff0c;第11.5節&#xff0c;一個動畫例子。 本例講解的是在一個繁星背景下&#xff0c;一個由經緯線組成的藍色…

math.sqrt 有問題_JavaScript中帶有示例的Math.SQRT2屬性

math.sqrt 有問題JavaScript | Math.SQRT2屬性 (JavaScript | Math.SQRT2 Property) Math.SQRT2 is a property in math library of JavaScript that is used to find the value of square root of 2. It is generally used to solve problems related to circular figures. Ma…

Linux內核設計與實現---系統調用

系統調用1 API、POSIX和C庫2 系統調用系統調用號3 系統調用處理程序指定恰當的系統調用參數傳遞4 系統調用的實現參數驗證5 系統調用上下文綁定一個系統調用的最后步驟從用戶空間訪問系統調用為什么不通過系統調用的方式實現1 API、POSIX和C庫 API&#xff1a;應用編程接口。一…

內核編譯配置選項含義

Linux 2.6.19.x 內核編譯配置選項簡介 作者&#xff1a;金步國 版權聲明 本文作者是一位自由軟件愛好者&#xff0c;所以本文雖然不是軟件&#xff0c;但是本著 GPL 的精神發布。任何人都可以自由使用、轉載、復制和再分發&#xff0c;但必須保留作者署名&#xff0c;亦不得對聲…

js編碼處理(轉)

js編碼處理(轉) 1. 使用 JS 中的 encodeURIComponent 或 encodeURI 方法。 說明&#xff1a; encodeURIComponent(String) 對傳遞參數進行設置。不編碼字符有 71 個&#xff1a; ! &#xff0c; &#xff0c; ( &#xff0c; ) &#xff0c; * &#xff0c; - &#…