Liste des colonnes avec des index dans PostgreSQL

233

Je voudrais obtenir les colonnes sur lesquelles se trouve un index dans PostgreSQL.

Dans MySQL, vous pouvez utiliser SHOW INDEXES FOR tableet consulter la Column_namecolonne.

mysql> show indexes from foos;

+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name            | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| foos  |          0 | PRIMARY             |            1 | id          | A         |       19710 |     NULL | NULL   |      | BTREE      |         | 
| foos  |          0 | index_foos_on_email |            1 | email       | A         |       19710 |     NULL | NULL   | YES  | BTREE      |         | 
| foos  |          1 | index_foos_on_name  |            1 | name        | A         |       19710 |     NULL | NULL   |      | BTREE      |         | 
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

Existe-t-il quelque chose comme ça pour PostgreSQL?

J'ai essayé \dà l' psqlinvite de commande (avec l' -Eoption d'afficher SQL) mais il n'affiche pas les informations que je recherche.

Mise à jour: Merci à tous ceux qui ont ajouté leurs réponses. cope360 m'a donné exactement ce que je cherchais, mais plusieurs personnes sont intervenues avec des liens très utiles. Pour référence future, consultez la documentation de pg_index (via Milen A. Radev ) et l'article très utile Extraire les informations META de PostgreSQL (via Michał Niklas ).

Luke Francl
la source
Juste pour clarifier: vous voulez que votre programme puisse déterminer, au moment de l'exécution, quelles colonnes sont indexées, non? Par opposition à vous la programmation sachant.
Wayne Conrad
Oui correct. Idéalement, je veux une instruction SQL qui répertorie UNIQUEMENT les colonnes sur lesquelles se trouve l'index. Mais je sais que PostgreSQL est plus compliqué que MySQL et que l'index pourrait être sur une fonction, etc.
Luke Francl

Réponses:

261

Créez des données de test ...

create table test (a int, b int, c int, constraint pk_test primary key(a, b));
create table test2 (a int, b int, c int, constraint uk_test2 unique (b, c));
create table test3 (a int, b int, c int, constraint uk_test3b unique (b), constraint uk_test3c unique (c),constraint uk_test3ab unique (a, b));

Liste des index et des colonnes indexés:

select
    t.relname as table_name,
    i.relname as index_name,
    a.attname as column_name
from
    pg_class t,
    pg_class i,
    pg_index ix,
    pg_attribute a
where
    t.oid = ix.indrelid
    and i.oid = ix.indexrelid
    and a.attrelid = t.oid
    and a.attnum = ANY(ix.indkey)
    and t.relkind = 'r'
    and t.relname like 'test%'
order by
    t.relname,
    i.relname;

 table_name | index_name | column_name
------------+------------+-------------
 test       | pk_test    | a
 test       | pk_test    | b
 test2      | uk_test2   | b
 test2      | uk_test2   | c
 test3      | uk_test3ab | a
 test3      | uk_test3ab | b
 test3      | uk_test3b  | b
 test3      | uk_test3c  | c

Roll up les noms des colonnes:

select
    t.relname as table_name,
    i.relname as index_name,
    array_to_string(array_agg(a.attname), ', ') as column_names
from
    pg_class t,
    pg_class i,
    pg_index ix,
    pg_attribute a
where
    t.oid = ix.indrelid
    and i.oid = ix.indexrelid
    and a.attrelid = t.oid
    and a.attnum = ANY(ix.indkey)
    and t.relkind = 'r'
    and t.relname like 'test%'
group by
    t.relname,
    i.relname
order by
    t.relname,
    i.relname;

 table_name | index_name | column_names
------------+------------+--------------
 test       | pk_test    | a, b
 test2      | uk_test2   | b, c
 test3      | uk_test3ab | a, b
 test3      | uk_test3b  | b
 test3      | uk_test3c  | c
cope360
la source
24
Pour toute personne essayant de trouver des index dans une base de données peuplée: cette requête fonctionne très bien, mais changez la and t.relname like 'test%'ligne en table (s) que vous voulez, ou effacez complètement cette ligne pour trouver tous les index dans votre base de données.
Erik J
1
Quelqu'un pourrait-il expliquer ce que cela relkind='r'signifie?
Qwerty
5
@Qwery, consultez la documentation de pg_class r = ordinary table, i = index, S = sequence, v = view, c = composite type, t = TOAST table.
cope360
1
existe-t-il un moyen de parler également de l'unicité de la clé?
Andrew
2
pour voir l'unicité de l'index, sélectionnez égalementix.indisunique
Jana
177

PostgreSQL ( pg_indexes ):

SELECT * FROM pg_indexes WHERE tablename = 'mytable';

MySQL ( MONTRER INDEX ):

SHOW INDEX FROM mytable;
Valentin Podkamennyi
la source
3
C'est la réponse la plus simple et la plus intéressante pour répondre à la question "Ma colonne est-elle indexée?" PostgreSQL: SELECT COUNT(indexname) AS indexcount FROM pg_indexes WHERE tablename='mytablename' AND indexdef LIKE '%mycolumnname%' ;et vérifiez indexcount>0. mySQL: SHOW INDEX FROM mytablename WHERE Column_name='mycolumnname' ;et vérifiez que le jeu de résultats n'est pas vide.
zerobandwidth
2
Bien qu'il s'agisse d'une réponse très utile en termes de récupération d'informations rapides sur les index, elle ne répond pas à la question d'origine car la pg_indexesvue ne fournit pas de noms de colonne. postgresql.org/docs/current/view-pg-indexes.html
akagixxer
146

\d table_nameaffiche ces informations psql, mais si vous souhaitez obtenir ces informations de la base de données en utilisant SQL, jetez un œil à Extraire les informations META de PostgreSQL .

J'utilise ces informations dans mon utilitaire pour signaler certaines informations du schéma db afin de comparer les bases de données PostgreSQL dans les environnements de test et de production.

Michał Niklas
la source
Votre lien pour extraire des méta-informations de Postgres est exactement ce que je cherchais! En utilisant les conseils de ce fil et quelques recherches, j'ai été assez proche de la requête qu'il utilise dans ce post, mais c'est bien d'avoir tout présenté comme ça.
Luke Francl
1
J'utilise AWS RDS PostgreSQL 9.6.5 et \d tablen'affiche aucun index, mais \diaffiche tous les index.
Hendy Irawan
@HendyIrawan, il peut apparemment être affecté par d'autres paramètres. Comme si je me demandais si vous aviez le mode "tuples seulement" activé (basculé par \t). Avec "tuples only" activé, je n'obtiens pas d'index \d, avec "tuples only" désactivé, je le fais. C'est avec psql (PostgreSQL) 9.6.15.
JMM
77

Faites juste: \d table_name

Mais je ne sais pas ce que tu veux dire par là que les informations sur les colonnes ne sont pas là.

Par exemple:

# \d pg_class
       Table "pg_catalog.pg_class"
     Column      |   Type    | Modifiers
-----------------+-----------+-----------
 relname         | name      | not null
 relnamespace    | oid       | not null
 reltype         | oid       | not null
 reloftype       | oid       | not null
 relowner        | oid       | not null
 relam           | oid       | not null
 relfilenode     | oid       | not null
 reltablespace   | oid       | not null
 relpages        | integer   | not null
 reltuples       | real      | not null
 reltoastrelid   | oid       | not null
 reltoastidxid   | oid       | not null
 relhasindex     | boolean   | not null
 relisshared     | boolean   | not null
 relistemp       | boolean   | not null
 relkind         | "char"    | not null
 relnatts        | smallint  | not null
 relchecks       | smallint  | not null
 relhasoids      | boolean   | not null
 relhaspkey      | boolean   | not null
 relhasexclusion | boolean   | not null
 relhasrules     | boolean   | not null
 relhastriggers  | boolean   | not null
 relhassubclass  | boolean   | not null
 relfrozenxid    | xid       | not null
 relacl          | aclitem[] |
 reloptions      | text[]    |
Indexes:
    "pg_class_oid_index" UNIQUE, btree (oid)
    "pg_class_relname_nsp_index" UNIQUE, btree (relname, relnamespace)

Il montre clairement quelles colonnes l'index donné se trouve sur cette table.

shilovk
la source
J'espérais quelque chose qui me permettrait de faire tous les index sur une table mais vous avez raison, \d index_namea les informations. Je peux donc rechercher les index sur une table, puis rechercher les détails. En ne montrant pas les colonnes, je veux dire que j'ai regardé le SQL généré par \d tablenom et il n'est pas évident pour moi d'où vient la liste des colonnes. Je pense qu'il est analysé hors de la définition de l'indice, ce que je préférerais ne pas faire.
Luke Francl
J'utilise AWS RDS PostgreSQL 9.6.5 et \d tablen'affiche aucun index, mais \diaffiche tous les index.
Hendy Irawan
37

# \di

La méthode la plus simple et la plus courte est la \diliste de tous les index de la base de données actuelle.

$ \di
                      List of relations
 Schema |            Name             | Type  |  Owner   |     Table     
--------+-----------------------------+-------+----------+---------------
 public | part_delivery_index         | index | shipper  | part_delivery
 public | part_delivery_pkey          | index | shipper  | part_delivery
 public | shipment_by_mandator        | index | shipper  | shipment_info
 public | shipment_by_number_and_size | index | shipper  | shipment_info
 public | shipment_info_pkey          | index | shipper  | shipment_info
(5 rows)

\diest le « petit frère » de la \dcommande qui liste toutes les relations du courant d atabase. Ainsi , une \dicertaine organisation pour « me montrer d atabases i ndexes ».

La \diSsaisie répertorie tous les index utilisés à l'échelle du système, ce qui signifie que vous obtenez également tous les index pg_catalog.

$ \diS
                                      List of relations
   Schema   |                   Name                    | Type  |  Owner   |          Table
------------+-------------------------------------------+-------+----------+-------------------------
 pg_catalog | pg_aggregate_fnoid_index                  | index | postgres | pg_aggregate
 pg_catalog | pg_am_name_index                          | index | postgres | pg_am
 pg_catalog | pg_am_oid_index                           | index | postgres | pg_am
 pg_catalog | pg_amop_fam_strat_index                   | index | postgres | pg_amop
 pg_catalog | pg_amop_oid_index                         | index | postgres | pg_amop
 pg_catalog | pg_amop_opr_fam_index                     | index | postgres | pg_amop
 pg_catalog | pg_amproc_fam_proc_index                  | index | postgres | pg_amproc
 pg_catalog | pg_amproc_oid_index                       | index | postgres | pg_amproc
 pg_catalog | pg_attrdef_adrelid_adnum_index            | index | postgres | pg_attrdef
--More-- 

Avec ces deux commandes, vous pouvez ajouter un +après pour obtenir encore plus d'informations comme la taille de l'espace disque dont l'index a besoin et une description si disponible.

$ \di+
                                 List of relations
 Schema |            Name             | Type  |  Owner   |     Table     | Size  | Description 
--------+-----------------------------+-------+----------+---------------+-------+-------------
 public | part_delivery_index         | index | shipper  | part_delivery | 16 kB | 
 public | part_delivery_pkey          | index | shipper  | part_delivery | 16 kB | 
 public | shipment_by_mandator        | index | shipper  | shipment_info | 19 MB | 
 public | shipment_by_number_and_size | index | shipper  | shipment_info | 19 MB | 
 public | shipment_info_pkey          | index | shipper  | shipment_info | 53 MB | 
(5 rows)

Dans psql, vous pouvez facilement trouver de l'aide sur la saisie des commandes \?.

sebisnow
la source
2
Mais il ne montre pas les noms des colonnes sur lesquelles les index sont créés. L'index des clés primaires composées a de nombreuses colonnes et celles-ci ne sont pas visibles.
Vignesh Raja
18

Combiné avec d'autres codes et créé une vue:

CREATE OR REPLACE VIEW view_index AS 
SELECT
     n.nspname  as "schema"
    ,t.relname  as "table"
    ,c.relname  as "index"
    ,pg_get_indexdef(indexrelid) as "def"
FROM pg_catalog.pg_class c
    JOIN pg_catalog.pg_namespace n ON n.oid        = c.relnamespace
    JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid
    JOIN pg_catalog.pg_class t ON i.indrelid   = t.oid
WHERE c.relkind = 'i'
    and n.nspname not in ('pg_catalog', 'pg_toast')
    and pg_catalog.pg_table_is_visible(c.oid)
ORDER BY
     n.nspname
    ,t.relname
    ,c.relname;
naoko
la source
12

Quelques exemples de données ...

create table test (a int, b int, c int, constraint pk_test primary key(a, b));
create table test2 (a int, b int, c int, constraint uk_test2 unique (b, c));
create table test3 (a int, b int, c int, constraint uk_test3b unique (b), constraint uk_test3c unique (c), constraint uk_test3ab unique (a, b));

Utiliser la pg_get_indexdeffonction:

select pg_get_indexdef(indexrelid) from pg_index where indrelid = 'test'::regclass;

                    pg_get_indexdef
--------------------------------------------------------
 CREATE UNIQUE INDEX pk_test ON test USING btree (a, b)
(1 row)


select pg_get_indexdef(indexrelid) from pg_index where indrelid = 'test2'::regclass;
                     pg_get_indexdef
----------------------------------------------------------
 CREATE UNIQUE INDEX uk_test2 ON test2 USING btree (b, c)
(1 row)


select pg_get_indexdef(indexrelid) from pg_index where indrelid ='test3'::regclass;
                      pg_get_indexdef
------------------------------------------------------------
 CREATE UNIQUE INDEX uk_test3b ON test3 USING btree (b)
 CREATE UNIQUE INDEX uk_test3c ON test3 USING btree (c)
 CREATE UNIQUE INDEX uk_test3ab ON test3 USING btree (a, b)
(3 rows)
cope360
la source
Simple et efficace!
David
Tout simplement génial. J'ai de la chance d'avoir fait défiler jusqu'à cette réponse.
greatvovan
8

Cette commande affiche également la vue des variables des tables, des index et des contraintes

=# \d table_name;

Exemple:

testannie=# \d dv.l_customer_account;
aryen
la source
7

\d tablename affiche les noms de colonne pour moi sur la version 8.3.8.

 "username_idx" UNIQUE, btree (username), tablespace "alldata1"
Corey
la source
7

RÉSULTAT DE LA DEMANDE:

table |     column     |          type          | notnull |  index_name  | is_index | primarykey | uniquekey | default
-------+----------------+------------------------+---------+--------------+----------+-   -----------+-----------+---------
 nodes | dns_datacenter | character varying(255) | f       |              | f        | f          | f         |
 nodes | dns_name       | character varying(255) | f       | dns_name_idx | t        | f          | f         |
 nodes | id             | uuid                   | t       | nodes_pkey   | t        | t          | t         |
(3 rows)

REQUETE:

SELECT  
c.relname AS table,
f.attname AS column,  
pg_catalog.format_type(f.atttypid,f.atttypmod) AS type,
f.attnotnull AS notnull,  
i.relname as index_name,
CASE  
    WHEN i.oid<>0 THEN 't'  
    ELSE 'f'  
END AS is_index,  
CASE  
    WHEN p.contype = 'p' THEN 't'  
    ELSE 'f'  
END AS primarykey,  
CASE  
    WHEN p.contype = 'u' THEN 't' 
    WHEN p.contype = 'p' THEN 't' 
    ELSE 'f'
END AS uniquekey,
CASE
    WHEN f.atthasdef = 't' THEN d.adsrc
END AS default  FROM pg_attribute f  
JOIN pg_class c ON c.oid = f.attrelid  
JOIN pg_type t ON t.oid = f.atttypid  
LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum  
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace  
LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey)  
LEFT JOIN pg_class AS g ON p.confrelid = g.oid
LEFT JOIN pg_index AS ix ON f.attnum = ANY(ix.indkey) and c.oid = f.attrelid and c.oid = ix.indrelid 
LEFT JOIN pg_class AS i ON ix.indexrelid = i.oid 

WHERE c.relkind = 'r'::char  
AND n.nspname = 'public'  -- Replace with Schema name 
--AND c.relname = 'nodes'  -- Replace with table name, or Comment this for get all tables
AND f.attnum > 0
ORDER BY c.relname,f.attname;
Dryymoon
la source
sympa, cependant le nom de "colonne" pour une colonne est un mot réservé. IDEM pour le schéma, doit utiliser nom_colonne
parisni
5

Les informations brutes se trouvent dans pg_index .

Milen A. Radev
la source
Intéressant. Plus précisément indkey: "Il s'agit d'un tableau de valeurs d'indnatts qui indiquent les colonnes de table indexées par cet index. Par exemple, une valeur de 1 3 signifierait que les première et troisième colonnes de table constituent la clé d'index. Un zéro dans ce tableau indique que le l'attribut d'index correspondant est une expression sur les colonnes de la table, plutôt qu'une simple référence de colonne "
Luke Francl
2

Si vous souhaitez conserver l'ordre des colonnes dans l'index, voici un moyen (très laid) de le faire:

select table_name,
    index_name,
    array_agg(column_name)
from (
    select
        t.relname as table_name,
        i.relname as index_name,
        a.attname as column_name,
        unnest(ix.indkey) as unn,
        a.attnum
    from
        pg_class t,
        pg_class i,
        pg_index ix,
        pg_attribute a
    where
        t.oid = ix.indrelid
        and i.oid = ix.indexrelid
        and a.attrelid = t.oid
        and a.attnum = ANY(ix.indkey)
        and t.relkind = 'r'
        and t.relnamespace = <oid of the schema you're interested in>
    order by
        t.relname,
        i.relname,
        generate_subscripts(ix.indkey,1)) sb
where unn = attnum
group by table_name, index_name

l'ordre des colonnes est stocké dans la colonne pg_index.indkey, j'ai donc ordonné par les indices de ce tableau.

David Willis
la source
2

Lorsque vous jouez avec des index, l'ordre dans lequel les colonnes sont construites dans l'index est aussi important que les colonnes elles-mêmes.

La requête suivante répertorie tous les index d'une table donnée et toutes leurs colonnes de manière triée.

SELECT
  table_name,
  index_name,
  string_agg(column_name, ',')
FROM (
       SELECT
         t.relname AS table_name,
         i.relname AS index_name,
         a.attname AS column_name,
         (SELECT i
          FROM (SELECT
                  *,
                  row_number()
                  OVER () i
                FROM unnest(indkey) WITH ORDINALITY AS a(v)) a
          WHERE v = attnum)
       FROM
         pg_class t,
         pg_class i,
         pg_index ix,
         pg_attribute a
       WHERE
         t.oid = ix.indrelid
         AND i.oid = ix.indexrelid
         AND a.attrelid = t.oid
         AND a.attnum = ANY (ix.indkey)
         AND t.relkind = 'r'
         AND t.relname LIKE 'tablename'
       ORDER BY table_name, index_name, i
     ) raw
GROUP BY table_name, index_name
user6654165
la source
2
Pourquoi le PO devrait-il "essayer ceci"? Une bonne réponse aura toujours une explication de ce qui a été fait et pourquoi cela a été fait de cette façon, non seulement pour l'OP mais pour les futurs visiteurs de SO qui peuvent trouver cette question et lire votre réponse.
Maximilian Ast
l' iordinalité est très lisse. Il garantit que les colonnes sont indiquées dans le bon ordre.
kbrock
Ce fut la seule réponse qui a fonctionné pour moi. L'ordre des colonnes est critique. (Si vous ne me croyez pas, recherchez toutes les personnes dont le prénom est Frank dans un annuaire.)
Juraj
1

Veuillez essayer la requête ci-dessous pour explorer les index requis

Interrogez comme ci-dessous - j'ai essayé personnellement et l'utilise fréquemment.

SELECT n.nspname as "Schema",
  c.relname as "Name",
  CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'i' 
THEN 'index' WHEN 'S' THEN 'sequence' WHEN 's' THEN 'special' END as "Type",
  u.usename as "Owner",
 c2.relname as "Table"
FROM pg_catalog.pg_class c
     JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid
     JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid
     LEFT JOIN pg_catalog.pg_user u ON u.usesysid = c.relowner
     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('i','')
      AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
      AND pg_catalog.pg_table_is_visible(c.oid)
      AND c2.relname like '%agg_transaction%' --table name
      AND nspname = 'edjus' -- schema name 
ORDER BY 1,2;
Barath Ravichander
la source
1

Similaire à la réponse acceptée mais avoir laissé la jointure sur pg_attribute comme jointure normale ou requête avec pg_attribute ne donne pas d'indices qui sont comme:
create unique index unique_user_name_index on users (lower(name))

select 
    row_number() over (order by c.relname),
    c.relname as index, 
    t.relname as table, 
    array_to_string(array_agg(a.attname), ', ') as column_names 
from pg_class c
join pg_index i on c.oid = i.indexrelid and c.relkind='i' and c.relname not like 'pg_%' 
join pg_class t on t.oid = i.indrelid
left join pg_attribute a on a.attrelid = t.oid and a.attnum = ANY(i.indkey) 
group by t.relname, c.relname order by c.relname;
Nikhil
la source
bonne note, mais comment obtenir des informations sur ce "lower (column_name") "
pleerock
1

Voici une fonction qui encapsule la réponse de cope360:

CREATE OR REPLACE FUNCTION getIndices(_table_name varchar)
  RETURNS TABLE(table_name varchar, index_name varchar, column_name varchar) AS $$
  BEGIN
    RETURN QUERY
    select
    t.relname::varchar as table_name,
    i.relname::varchar as index_name,
    a.attname::varchar as column_name
from
    pg_class t,
    pg_class i,
    pg_index ix,
    pg_attribute a
where
    t.oid = ix.indrelid
    and i.oid = ix.indexrelid
    and a.attrelid = t.oid
    and a.attnum = ANY(ix.indkey)
    and t.relkind = 'r'
    and t.relname = _table_name
order by
    t.relname,
    i.relname;
  END;
  $$ LANGUAGE plpgsql;

Usage:

select * from getIndices('<my_table>')
chribsen
la source
N'a pas répertorié les parties de mes index qui utilisent des fonctions (par exemple, "upper (field_name)").
JohnMudd
0

Que diriez-vous d'une solution simple:

SELECT 
  t.relname table_name,
  ix.relname index_name,
  indisunique,
  indisprimary, 
  regexp_replace(pg_get_indexdef(indexrelid), '.*\((.*)\)', '\1') columns
FROM pg_index i
JOIN pg_class t ON t.oid = i.indrelid
JOIN pg_class ix ON ix.oid = i.indexrelid
WHERE t.relname LIKE 'test%'

"

Alex
la source
J'adore cette solution. Malheureusement, il échoue avec les index contenant des clauses where. (ou autre parenthèse)
kbrock
J'ai changé pour ne pas ignorer les parens au début, et ne pas capturer les parens au milieu, et tout laisser tomber après cela. '^[^\)]*\(([^\)]*)\).*$'
kbrock
0

Excellente réponse de @ cope360, convertie pour utiliser la syntaxe de jointure.

select t.relname as table_name
     , i.relname as index_name
     , array_to_string(array_agg(a.attname), ', ') as column_names
from pg_class t
join pg_index ix
on t.oid = ix.indrelid
join pg_class i
on i.oid = ix.indexrelid
join pg_attribute a
on a.attrelid = t.oid
and a.attnum = ANY(ix.indkey)
where t.relkind = 'r'
and t.relname like 'test%'
group by t.relname
       , i.relname
order by t.relname
       , i.relname
;
Christian Long
la source
0

Je ne pense pas que cette version existe encore sur ce fil: elle fournit à la fois la liste des noms de colonnes ainsi que le ddl pour l'index.

CREATE OR REPLACE VIEW V_TABLE_INDEXES AS

SELECT
     n.nspname  as "schema"
    ,t.relname  as "table"
    ,c.relname  as "index"
    ,i.indisunique AS "is_unique"
    ,array_to_string(array_agg(a.attname), ', ') as "columns"
    ,pg_get_indexdef(i.indexrelid) as "ddl"
FROM pg_catalog.pg_class c
    JOIN pg_catalog.pg_namespace n ON n.oid        = c.relnamespace
    JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid
    JOIN pg_catalog.pg_class t ON i.indrelid   = t.oid
    JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(i.indkey)
WHERE c.relkind = 'i'
      and n.nspname not in ('pg_catalog', 'pg_toast')
      and pg_catalog.pg_table_is_visible(c.oid)
GROUP BY
    n.nspname
    ,t.relname
    ,c.relname
    ,i.indisunique
    ,i.indexrelid
ORDER BY
    n.nspname
    ,t.relname
    ,c.relname;

J'ai trouvé que les index utilisant des fonctions ne sont pas liés aux noms de colonnes, donc parfois vous trouvez une liste d'index, par exemple un nom de colonne alors qu'en fait, il utilise 3.

Exemple:

CREATE INDEX ui1 ON table1 (coalesce(col1,''),coalesce(col2,''),col3)

La requête renvoie uniquement «col3» en tant que colonne sur l'index, mais la DDL affiche l'ensemble complet des colonnes utilisées dans l'index.

datico
la source
0

Étendre à la bonne réponse de @ Cope360. Pour obtenir une certaine table (au cas où il s'agit du même nom de table mais d'un schéma différent), il suffit d'utiliser la table OID.

select
     t.relname as table_name
    ,i.relname as index_name
    ,a.attname as column_name
    ,a.attrelid tableid

from
    pg_class t,
    pg_class i,
    pg_index ix,
    pg_attribute a
where
    t.oid = ix.indrelid
    and i.oid = ix.indexrelid
    and a.attrelid = t.oid
    and a.attnum = ANY(ix.indkey)
    and t.relkind = 'r'
    -- and t.relname like 'tbassettype'
    and a.attrelid = '"dbLegal".tbassettype'::regclass
order by
    t.relname,
    i.relname;

Expliquez: J'ai le nom de table «tbassettype» dans le schéma «dbAsset» et «dbLegal». Pour obtenir uniquement une table sur dbLegal, laissez simplement a.attrelid = son OID.

Wutikrai
la source
0

Une réponse un peu modifiée de @ cope360:

create table test (a int, b int, c int, constraint pk_test primary key(c, a, b));
select i.relname as index_name,
       ix.indisunique as is_unique,
       a.attname as column_name,
from pg_class c
       inner join pg_index ix on c.oid=ix.indrelid
       inner join pg_class i on ix.indexrelid=i.oid
       inner join pg_attribute a on a.attrelid=c.oid and a.attnum=any(ix.indkey)
where c.oid='public.test'::regclass::oid
order by array_position(ix.indkey, a.attnum) asc;

Cela affichera les colonnes d'index dans l'ordre correct:

index_name      is_unique  column_name
pk_test         true       c
pk_test         true       a
pk_test         true       b
Nikita Ryanov
la source
L'utilisation de "left join pg_attribute" affichera également les index sur les colonnes calculées, bien sûr avec un nom_colonne NULL.
Paolo Bonzini
0
select t.relname as table_name, 
       i.relname as index_name, 
       array_position(ix.indkey,a.attnum) pos, 
       a.attname as column_name
from pg_class t
join pg_index ix on t.oid = ix.indrelid
join pg_class i on i.oid = ix.indexrelid
join pg_attribute a on a.attrelid = t.oid and a.attnum = ANY(ix.indkey)
where t.relkind = 'r'
and t.relname like 'orders'
order by t.relname, i.relname, array_position(ix.indkey,a.attnum)
Guy Cohen
la source
0

La réponse acceptée par @ cope360 est bonne, mais je voulais quelque chose d'un peu plus comme DBA_IND_COLUMNS, ALL_IND_COLUMNS et USER_IND_COLUMNS d'Oracle (par exemple, rapporte le schéma de table / index et la position de l'index dans un index multicolonne), j'ai donc adapté l'accepté répondre à ceci:

with
 ind_cols as (
select
    n.nspname as schema_name,
    t.relname as table_name,
    i.relname as index_name,
    a.attname as column_name,
    1 + array_position(ix.indkey, a.attnum) as column_position
from
     pg_catalog.pg_class t
join pg_catalog.pg_attribute a on t.oid    =      a.attrelid 
join pg_catalog.pg_index ix    on t.oid    =     ix.indrelid
join pg_catalog.pg_class i     on a.attnum = any(ix.indkey)
                              and i.oid    =     ix.indexrelid
join pg_catalog.pg_namespace n on n.oid    =      t.relnamespace
where t.relkind = 'r'
order by
    t.relname,
    i.relname,
    array_position(ix.indkey, a.attnum)
)
select * 
from ind_cols
where schema_name = 'test'
  and table_name  = 'indextest'
order by schema_name, table_name
;

Cela donne une sortie comme:

 schema_name | table_name | index_name | column_name | column_position 
-------------+------------+------------+-------------+-----------------
 test        | indextest  | testind1   | singleindex |               1
 test        | indextest  | testind2   | firstoftwo  |               1
 test        | indextest  | testind2   | secondoftwo |               2
(3 rows)
Stephen
la source