索引推薦(index_adviser)可以幫助您確定應該對哪些列編制索引,以提高指定工作負載中的性能。索引推薦僅識別B樹索引類型(單列或復合),不識別可提高性能的其他索引類型,例如GIN、GiST、Hash等。
您可以加入RDS PostgreSQL插件交流釘釘群(103525002795),進行咨詢、交流和反饋,獲取更多關于插件的信息。
前提條件
實例內核小版本為20230830或以上。
20230830內核小版本之前已支持此插件,但為了規范插件管理,提升RDS PostgreSQL在插件側的安全防護,RDS計劃在內核版本迭代中陸續對部分存在安全風險的插件進行優化,部分插件在低內核小版本無法創建,更多信息,請參見【產品/功能變更】RDS PostgreSQL限制創建插件說明。
如果您的實例內核小版本低于20230830,且已經使用了此插件,則不影響使用。
如果您首次創建或重新創建此插件,請升級內核小版本到最新。
索引推薦(index_adviser)組件
執行創建索引推薦插件語句時,同時會創建index_advisory表、show_index_advisory()函數和select_index_advisory視圖。
組件 | 說明 |
index_advisory | 此表在創建索引推薦(index_adviser)插件時自動創建,將索引編制建議記錄在index_advisory表中。 |
show_index_advisory() | show_index_advisory()是一個PL/pgSQL函數,它解釋并顯示特定的索引推薦會話(由其后端進程ID標識)期間提出的建議。 |
select_index_advisory | 索引推薦(index_adviser)根據查詢分析期間存儲在index_advisory表中的信息,創建select_index_advisory視圖。該視圖所生成輸出的格式與show_index_advisory()函數的相同,顯示所有索引推薦會話期間提出的建議。 |
使用方法
創建index_adviser插件
postgres=# create extension index_adviser; CREATE EXTENSION
加載index_adviser插件
postgres=# LOAD 'index_adviser'; LOAD
說明以上加載語句只對當前會話有效。如果您希望所有會話都默認加載index_adviser,您需要配置shared_preload_libraries參數并重啟實例(會對性能有一些影響),配置方法如下:
shared_preload_libraries='index_adviser'
使用示例
創建表
CREATE TABLE t( a INT, b INT ); INSERT INTO t SELECT s, 99999 - s FROM generate_series(0,99999) AS s; ANALYZE t; 所生成的表包含以下各行: a | b -------+------- 0 | 99999 1 | 99998 2 | 99997 3 | 99996 . . . 99997 | 2 99998 | 1 99999 | 0
查詢單條SQL建議
如果您希望索引推薦分析查詢并提出索引編制建議但不實際執行查詢,請將EXPLAIN關鍵字作為SQL語句的前綴,示例如下:
postgres=# EXPLAIN SELECT * FROM t WHERE a < 10000; QUERY PLAN --------------------------------------------------------------------------------- Seq Scan on t (cost=0.00..1693.00 rows=9983 width=8) Filter: (a < 10000) Result (cost=0.00..0.00 rows=0 width=0) One-Time Filter: '** plan (using Index Adviser) **'::text -> Index Scan using "<1>t_a_idx" on t (cost=0.42..256.52 rows=9983 width=8) Index Cond: (a < 10000) (6 rows)
postgres=# EXPLAIN SELECT * FROM t WHERE a = 100; QUERY PLAN ---------------------------------------------------------------------------- Seq Scan on t (cost=0.00..1693.00 rows=1 width=8) Filter: (a = 100) Result (cost=0.00..0.00 rows=0 width=0) One-Time Filter: '** plan (using Index Adviser) **'::text -> Index Scan using "<1>t_a_idx" on t (cost=0.42..2.64 rows=1 width=8) Index Cond: (a = 100) (6 rows)
postgres=# EXPLAIN SELECT * FROM t WHERE b = 10000; QUERY PLAN ---------------------------------------------------------------------------- Seq Scan on t (cost=0.00..1693.00 rows=1 width=8) Filter: (b = 10000) Result (cost=0.00..0.00 rows=0 width=0) One-Time Filter: '** plan (using Index Adviser) **'::text -> Index Scan using "<1>t_b_idx" on t (cost=0.42..2.64 rows=1 width=8) Index Cond: (b = 10000) (6 rows)
您可通過psql命令行查詢index_advisory表內存儲的索引編制建議,示例如下:
postgres=# SELECT * FROM index_advisory; reloid | relname | attrs | benefit | original_cost | new_cost | index_size | backend_pid | timestamp --------+---------+-------+---------+---------------+----------+------------+-------------+---------------------------------- 16438 | t | {1} | 1337.43 | 1693 | 355.575 | 2624 | 79370 | 18-JUN-21 08:55:51.492388 +00:00 16438 | t | {1} | 1684.56 | 1693 | 8.435 | 2624 | 79370 | 18-JUN-21 08:59:00.319336 +00:00 16438 | t | {2} | 1684.56 | 1693 | 8.435 | 2624 | 79370 | 18-JUN-21 08:59:07.814453 +00:00 (3 rows)
列名
類型
描述
reloid
oid
索引的基表的OID。
relname
name
索引的基表的名稱。
attrs
integer[]
生成建議的索引列(由列編號標識)。
benefit
real
此查詢的索引的計算收益。
original_cost
real
使用索引之前的平均代價(即執行SQL的預估時間)。
new_cost
real
使用索引之后的平均代價(即執行SQL的預估時間)。
index_size
integer
磁盤頁中的估計索引大小。
backend_pid
integer
生成此建議的進程ID。
timestamp
timestamp
生成此建議的日期及時間。
如果語句不帶EXPLAIN關鍵字前綴,索引推薦將在語句執行期間分析語句并記錄建議。
說明不得在只讀事務中運行索引推薦(index_adviser)。
查詢WorkLoad級別建議
通過show_index_advisory()函數獲取單個會話的WorkLoad建議
此函數用于獲取單個會話的索引推薦(由后端進程ID標識),您可通過指定會話的進程ID來調用該函數:
SELECT show_index_advisory( pid );
說明pid指當前會話的進程ID,您可以在index_advisory表中查看backend_pid參數來獲得。您也可以將null作為傳遞值為當前會話返回結果集。
postgres=# SELECT show_index_advisory(null); show_index_advisory ---------------------------------------------------------------------------------------------------------------------------------------------------- create index idx_t_a on public.t(a);/* size: 2624 KB, benefit: 3021.99, gain: 1.15167301457103, original_cost: 1693, new_cost: 182.005006313324 */ create index idx_t_b on public.t(b);/* size: 2624 KB, benefit: 1684.56, gain: 0.641983590474943, original_cost: 1693, new_cost: 8.4350004196167 */ (2 rows)
說明結果集中每行的表示意義如下:
創建索引推薦建議的索引所需的SQL語句。
索引頁的估計大小。
使用索引的總收益(benefit)。
使用索引的增益(gain=benefit/size)。
使用索引之前的平均代價(即執行SQL的預估時間)。
使用索引之后的平均代價(即執行SQL的預估時間)。
通過select_index_advisory視圖獲取所有會話的WorkLoad建議
此視圖包含計算的指標和CREATE INDEX語句,展示當前位于index_advisory表中所有會話的索引編制建議。表t中列a和列b的索引編制建議顯示如下:
postgres=# SELECT * FROM select_index_advisory; backend_pid | show_index_advisory -------------+---------------------------------------------------------------------------------------------------------------------------------------------------- 79370 | create index t_a_idx on public.t(a);/* size: 2624 KB, benefit: 3021.99, gain: 1.15167301457103, original_cost: 1693, new_cost: 182.005006313324 */ 79370 | create index t_b_idx on public.t(b);/* size: 2624 KB, benefit: 1684.56, gain: 0.641983590474943, original_cost: 1693, new_cost: 8.4350004196167 */ (2 rows)
在每個會話中,從同一建議的索引中受益的所有查詢的結果將被組合起來,以便按每個建議的索引生成一組指標,此指標反映在名為benefit和gain的字段中,字段公式如下所示:
size = MAX(index size of all queries) benefit = SUM(benefit of each query) gain = SUM(benefit of each query) / MAX(index size of all queries)
說明如果單條SQL建議同時創建多個索引,則index_advisory表中記錄的new_cost為創建了多個索引之后的代價,而非創建某一個索引之后的代價。
當對給定會話期間得到的不同建議索引的相對優勢進行比較時,gain指標十分有用。gain值越大,從索引中得到的成本效益就越高,這可以抵消索引可能消耗的磁盤空間。