Goal Find indexed textual columns where the indexing does not consider the possibility of pattern-based search. Such columns do not have an index where the used operator class makes the index suitable for use by queries involving pattern matching expressions.
Notes The query considers only secondary indexes, i.e., indexes that are non-unique, non-function based, and that do not support any constraint. The query excludes foreign key columns because these are usally not used in pattern-matching queries.
Type Problem detection (Each row in the result could represent a flaw in the design)
Reliability Low (Many false-positive results)
License MIT License
Fixing Suggestion Create an index (instead of the index or in addition to the index) where text, varchar, char columns have the operator class text_pattern_ops, varchar_pattern_ops, or char_pattern_ops, respectively. An example: CREATE INDEX test_index ON test_table (col varchar_pattern_ops);
Data Source INFORMATION_SCHEMA+system catalog
SQL Query
WITH index_op_class AS (SELECT indexrelid, indrelid, indisunique, op_class, ordin
FROM pg_index, unnest(indclass) with ordinality AS k(op_class, ordin)
WHERE indexprs IS NULL
AND indisunique='f'),
indexes AS (SELECT 
  n.nspname AS table_schema,
  c2.relname AS table_name,
  a.attname AS column_name,
  c.relname AS index_name,
  ordin AS ordinal_position,  
  opcname AS operator_class
FROM 
  pg_class AS c INNER JOIN index_op_class AS i ON i.indexrelid = c.oid
  INNER JOIN pg_class AS c2  ON i.indrelid = c2.oid
  INNER JOIN pg_namespace AS n ON c.relnamespace = n.oid
  INNER JOIN pg_authid AS u ON  n.nspowner = u.oid
  INNER JOIN pg_attribute AS a ON a.attrelid = c.oid AND a.attnum=i.ordin
  INNER JOIN pg_opclass AS oc ON i.op_class=oc.oid
WHERE c.relkind = 'i'
AND a.attnum>=1
AND a.attisdropped = FALSE
AND (n.nspname = 'public'
	 OR u.rolname <> 'postgres')
AND NOT EXISTS (SELECT * FROM pg_catalog.pg_constraint AS o WHERE o.conindid=i.indexrelid)),
fk_columns AS (select target_schema as table_schema, target_table as table_name, a.attname as column_name
from (select 
(select nspname from pg_namespace where oid=m.relnamespace) as target_schema,
m.relname as target_table, 
m.oid as target_table_oid,
unnest(o.conkey) AS target_col
from pg_constraint o inner join pg_class c on c.oid = o.conrelid
inner join pg_class m on m.oid = o.conrelid
where o.contype='f'
and o.conrelid in (select oid from pg_class c where c.relkind = 'r')) t
inner join pg_attribute a on t.target_col = a.attnum and t.target_table_oid = a.attrelid and a.attisdropped = false),
textual_columns AS (SELECT table_schema, table_name, column_name
FROM INFORMATION_SCHEMA.columns
WHERE data_type IN ('text', 'character','character varying') AND 
(table_schema, table_name) IN (SELECT table_schema, table_name
FROM INFORMATION_SCHEMA.tables WHERE table_type='BASE TABLE') AND 
table_schema NOT IN (SELECT schema_name
FROM INFORMATION_SCHEMA.schemata
WHERE schema_name<>'public' AND
schema_owner='postgres' AND schema_name IS NOT NULL))
SELECT table_schema, table_name, column_name, index_name, operator_class
FROM indexes AS i
WHERE (table_schema, table_name, column_name) IN (SELECT table_schema, table_name, column_name
FROM textual_columns)
AND  (table_schema, table_name, column_name) NOT IN (SELECT table_schema, table_name, column_name
FROM fk_columns)
AND operator_class NOT LIKE '%\_pattern_ops'
AND NOT EXISTS (SELECT *
FROM indexes AS i2
WHERE i.table_schema=i2.table_schema
AND i.table_name=i2.table_name
AND i.column_name=i2.column_name
AND i2.operator_class LIKE '%\_pattern_ops')
ORDER BY table_schema, index_name, ordinal_position;

Collections

This query belongs to the following collections:

NameDescription
Find problems automaticallyQueries, that results point to problems in the database. Each query in the collection produces an initial assessment. However, a human reviewer has the final say as to whether there is a problem or not .
Categories

This query is classified under the following categories:

NameDescription
PerformanceQueries of this category provide information about indexes in a database.

Further reading and related materials:

Reference
https://www.postgresql.org/docs/current/indexes-opclass.html