常見的導致PG建立索引慢的原因

T1YSL發表於2023-03-31

1.表的大小問題

如果表的資料很多,索引建立在大表上的時候,會導致建索引的時間很慢。所以如果表的資料量很多,可以考慮重新設計表結構或拆分表。

可以考慮使用分割槽表,使用分割槽表來分割資料。這樣在建立索引時,可以只對需要建立索引的分割槽進行操作,從而提高索引建立的速度。

2.索引型別

不同型別的索引建立的速度可能會有所不同,因為儲存的結構不一致。例如,B-tree索引通常比GiST索引建立得更快。不同的索引策略適用於不同的場景,選擇合適的索引策略可以提高建索引的速度和效率。因此,可以考慮更改索引型別,以便更快地建立索引。

3.檢視伺服器負載

檢查系統是否存在其他程式佔用了大量的系統資源,如CPU、記憶體和磁碟IO等。可以使用top和vmstat,iostat等工具檢視。

4.磁碟空間

如果磁碟空間不足,可能會導致索引建立速度變慢。因此,可以檢查磁碟空間是否充足,並清理不需要的檔案。

5.檢查併發連線數

如果併發連線數過高,可能會導致建索引的速度變慢。可以調整PG的最大併發連線數引數,以避免過多的連線影響建索引的效能。

6.禁用觸發器和約束

在建立索引時,可以考慮禁用觸發器和約束,以避免對建立索引的影響。完成索引建立後,再重新啟用觸發器和約束。

禁用觸發器

ALTER TABLE TABLE_NAME DISABLE TRIGGER trigger_name;

開啟觸發器

ALTER TABLE TABLE_NAME ENABLE TRIGGER trigger_name;

禁用/開啟一張表上所有觸發器

ALTER TABLE table_name DISABLE TRIGGER all;
ALTER TABLE table_name ENABLE TRIGGER all;

這裡 all 會禁用表上的所有外來鍵,同時也禁用負責驗證約束的內部觸發器, all 也存在一些限制,就是你必須是超級使用者才能執行此操作。

7.透過調整引數來使用更多的記憶體建立索引

maintenance_work_mem預設值(64MB)是很低的,它是用於維護任務的記憶體設定,會影響於VACUUM,RESTORE,CREATE INDEX,ADD FOREIGN KEY和ALTER TABLE等操作的效能。使用更多的記憶體空間時建立索引的速度提升會非常明顯。在建立索引的時候,它控制構建索引時使用的最大記憶體量。構建B樹索引時,必須對資料排序,如果要排序的資料在maintenance_work_mem記憶體中放置不下,它將會溢位到磁碟中。
因此在執行CREATE INDEX命令之前,可以在本地會話中使用SET命令臨時增加該值。

shared_buffers和work_mem引數:shared_buffers決定了PG在記憶體中快取資料的大小,work_mem引數決定了其記憶體中執行sort和hash操作所能使用的記憶體大小。
如果這兩個引數設定不合理,也可能會導致索引建立速度變慢。

8.PG支援並行建索引

在建立索引時可以使用並行建索引的方式,以提高建索引的速度。

在postgreSQL11之後的版本中,新增了並行建立索引的功能,能夠提供多核索引建立功能。

並行程式數設定分為兩類,第一類是並行查詢,並行查詢的並行度由 max_parallel_workers_per_gather引數控制,第二類是維護命令(例如 CREATE INDEX),維護命令的並行度由 max_parallel_maintenance_workers 引數控制。

在postgreSQL中,預設情況下啟用並行索引建立。當在使用4個cpu核心的情況下建立索引,且max_parallel_maintenance_workers設定成4的時候,會使用4個核去並行建立。所使用並行數也受限於所擁有的cpu核數,當max_parallel_maintenance_workers設定的值超過了cpu核數,因為其cpu核數並沒有多餘的供它使用,所以引數多的部分並沒有意義。

可透過 ALTER TABLE 方式禁止表上的並行建立索引,如下禁止表t1上的所有並行建立索引

ALTER TABLE t1 SET (parallel_workers=0);

如果想恢復指定表上的parallel_workers引數設定,可採用如下方式

ALTER TABLE t1 RESET(parallel_workers);

9.使用SSD硬碟

SSD硬碟相比傳統的機械硬碟具有更快的讀寫速度,可以顯著提高索引建立的速度。

10.檢查鎖競爭情況

鎖競爭可能導致索引建立速度變慢。可以透過pg_locks檢視進行檢查是否有相關阻塞。

11.使用預熱功能

PG支援使用pg_prewarm外掛來預載入資料,可以在建立索引之前預先載入資料到記憶體中,以提高索引建立的速度。

12.使用Partial Index(部分索引)

PG可以針對表列的部分資料建立索引,來減小索引的大小,從而加快建立索引的速率。它是在表的一個子部分上構造的。在建索引時可以設定過濾條件,只對符合條件的資料建立索引。這樣可以減少索引的大小和建立索引的時間,從而提高索引建立的速度。舉例如下:

postgres=# create table t1(id int);
CREATE TABLE
postgres=# ALTER TABLE t1 RESET(parallel_workers);
ALTER TABLE
postgres=# create index t1_idx on t1(id) where id<5;
CREATE INDEX
postgres=# \d t1
                 Table "public.t1"
 Column |  Type   | Collation | Nullable | Default 
--------+---------+-----------+----------+---------
 id     | integer |           |          | 
Indexes:
    "t1_idx" btree (id) WHERE id < 5

13.避免使用大事務

在建索引時,儘量避免使用大事務。大事務會佔用大量的系統資源,可能會導致索引建立速度變慢。可以將事務拆分成多個小事務來處理,從而提高建索引的速度和效率。

14.避免同時建立多個索引

多個索引會增加系統負擔,可能會導致索引建立速度變慢。可以透過合併索引來最佳化建索引的速度和效率。此外,因為PG可以在同一列上建立多個索引。這些索引可能僅名字不一樣,這個時候,多餘的索引既會在DML操作的時候佔用資源,也會在對錶做操作的時候反饋慢。所以,合理規劃索引,不建立重複索引也是比較且容易忽視的一點。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69990629/viewspace-2942947/,如需轉載,請註明出處,否則將追究法律責任。

相關文章