删除不可用的索引是否更好?

Is it better to delete non-usable indexes?

下面的查询结果显示了索引统计历史。如果我删除 TotalNumberOfScan0 的 return 值的索引会更好吗?

SELECT
pt.tablename AS TableName
,t.indexname AS IndexName
,pc.reltuples 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
,t.idx_scan AS TotalNumberOfScan
,t.idx_tup_read AS TotalTupleRead
,t.idx_tup_fetch 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;

您绝对应该删除不使用的索引。索引可以加快某些操作的速度,但要付出代价 - 每次插入、删除或某些更新发生时都需要更新索引。

Here is a great post about the cost of maintaining additional indexes on update, here on delete and here 插入。例如,插入有 2 个索引的 table 的时间几乎是具有一个索引的相同 table 的两倍。

这是我查找所有无用索引的黄金标准查询:

SELECT s.schemaname,
       s.relname AS tablename,
       s.indexrelname AS indexname,
       pg_relation_size(s.indexrelid) AS index_size
FROM pg_catalog.pg_stat_user_indexes s
   JOIN pg_catalog.pg_index i ON s.indexrelid = i.indexrelid
WHERE s.idx_scan = 0      -- has never been scanned
  AND 0 <>ALL (i.indkey)  -- no index column is an expression
  AND NOT i.indisunique   -- is not a UNIQUE index
  AND NOT EXISTS          -- does not enforce a constraint
         (SELECT 1 FROM pg_catalog.pg_constraint c
          WHERE c.conindid = s.indexrelid)
ORDER BY pg_relation_size(s.indexrelid) DESC;

您需要考虑索引除了加速 WHEREORDER BY 子句之外还有其他用途:

  • 许多约束是通过索引实现的,例如主键。

  • 表达式上的索引使 PostgreSQL 收集索引表达式的统计信息,这可以帮助优化器。

详情见my blog