PostgreSQL索引使用分析

Cer*_*rin 81 sql postgresql database-design

是否有工具或方法来分析Postgres,并确定应创建哪些缺失索引​​,以及应删除哪些未使用的索引?我对使用SQLServer的"profiler"工具有一点经验,但我不知道Postgres附带的类似工具.

gue*_*tli 154

我喜欢这样找到缺失的索引:

SELECT
  relname                                               AS TableName,
  to_char(seq_scan, '999,999,999,999')                  AS TotalSeqScan,
  to_char(idx_scan, '999,999,999,999')                  AS TotalIndexScan,
  to_char(n_live_tup, '999,999,999,999')                AS TableRows,
  pg_size_pretty(pg_relation_size(relname :: regclass)) AS TableSize
FROM pg_stat_all_tables
WHERE schemaname = 'public'
      AND 50 * seq_scan > idx_scan -- more then 2%
      AND n_live_tup > 10000
      AND pg_relation_size(relname :: regclass) > 5000000
ORDER BY relname ASC;
Run Code Online (Sandbox Code Playgroud)

这将检查是否有更多序列扫描然后索引扫描.如果表很小,它会被忽略,因为Postgres似乎更喜欢对它们进行序列扫描.

以上查询确实显示缺失的索引.

下一步是检测缺失的组合索引.我想这不容易,但可行.也许分析慢查询...我听说pg_stat_statements可以帮助...

  • 要使用带引号的标识符进行此操作,请将查询更改为:`SELECT relname,seq_scan-idx_scan AS too_much_seq,seq_scan-idx_scan> 0那么'缺少索引?' ELSE'OK'END,pg_relation_size(relid :: regclass)AS rel_size,seq_scan,idx_scan FROM pg_stat_all_tables WHERE schemaname ='public'AND pg_relation_size(relid :: regclass)> 80000 ORDER BY too_much_seq DESC;` (12认同)
  • 应解释此查询的输出以使答案更有帮助 (9认同)

Fra*_*ens 19

检查统计数据.pg_stat_user_tables并且pg_stat_user_indexes是开始的.

请参阅" 统计信息收集器 ".


Shr*_*ash 11

可以通过在 postgres 控制台中使用以下查询找到它

use db_name
select * from pg_stat_user_indexes;
select * from pg_statio_user_indexes;
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息https://www.postgresql.org/docs/current/monitoring-stats.html


rfu*_*sca 8

关于确定缺失索引的方法....不.但是有一些计划在未来的版本中使这更容易,比如伪索引和机器可读的EXPLAIN.

目前,您需要EXPLAIN ANALYZE执行较差的查询,然后手动确定最佳路线.像pgFouine这样的日志分析器可以帮助确定查询.

对于未使用的索引,您可以使用以下内容来帮助识别它们:

select * from pg_stat_all_indexes where schemaname <> 'pg_catalog';
Run Code Online (Sandbox Code Playgroud)

这将有助于识别读取,扫描,提取的元组.


n10*_*000 7

另一个用于分析PostgreSQL的新的有趣工具是PgHero.它更侧重于调整数据库并进行大量分析和建议.

截图


Anv*_*esh 7

您可以使用以下查询来查找索引使用情况和索引大小:

参考来自此博客。

SELECT
    pt.tablename AS TableName
    ,t.indexname AS IndexName
    ,to_char(pc.reltuples, '999,999,999,999') AS TotalRows
    ,pg_size_pretty(pg_relation_size(quote_ident(pt.tablename)::text)) AS TableSize
    ,pg_size_pretty(pg_relation_size(quote_ident(t.indexrelname)::text)) AS IndexSize
    ,to_char(t.idx_scan, '999,999,999,999') AS TotalNumberOfScan
    ,to_char(t.idx_tup_read, '999,999,999,999') AS TotalTupleRead
    ,to_char(t.idx_tup_fetch, '999,999,999,999') AS TotalTupleFetched
FROM pg_tables AS pt
LEFT OUTER JOIN pg_class AS pc 
    ON pt.tablename=pc.relname
LEFT OUTER JOIN
( 
    SELECT 
        pc.relname AS TableName
        ,pc2.relname AS IndexName
        ,psai.idx_scan
        ,psai.idx_tup_read
        ,psai.idx_tup_fetch
        ,psai.indexrelname 
    FROM pg_index AS pi
    JOIN pg_class AS pc 
        ON pc.oid = pi.indrelid
    JOIN pg_class AS pc2 
        ON pc2.oid = pi.indexrelid
    JOIN pg_stat_all_indexes AS psai 
        ON pi.indexrelid = psai.indexrelid 
)AS T
    ON pt.tablename = T.TableName
WHERE pt.schemaname='public'
ORDER BY 1;
Run Code Online (Sandbox Code Playgroud)