Elenca le colonne con gli indici in PostgreSQL


233

Vorrei ottenere le colonne su cui si trova un indice in PostgreSQL.

In MySQL puoi usare SHOW INDEXES FOR tablee guardare la Column_namecolonna.

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      |         | 
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

Esiste qualcosa di simile per PostgreSQL?

Ho provato \dal psqlprompt dei comandi (con l' -Eopzione per mostrare SQL) ma non mostra le informazioni che sto cercando.

Aggiornamento: grazie a tutti coloro che hanno aggiunto le loro risposte. cope360 mi ha dato esattamente quello che stavo cercando, ma diverse persone sono intervenute con collegamenti molto utili. Per riferimenti futuri, consulta la documentazione di pg_index (via Milen A. Radev ) e l'articolo molto utile Estrarre informazioni META da PostgreSQL (via Michał Niklas ).


Solo per chiarire: vuoi che il tuo programma sia in grado di capire, in fase di esecuzione, quali colonne sono indicizzate, giusto? Al contrario di te la conoscenza della programmazione.
Wayne Conrad,

Si corretto. Idealmente, voglio un'istruzione SQL che elenca SOLO le colonne su cui si trova l'indice. Ma so che PostgreSQL è più complicato di MySQL e l'indice potrebbe essere su una funzione, ecc.
Luke Francl

Risposte:


261

Crea alcuni dati di 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));

Elenca gli indici e le colonne indicizzate:

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 dei nomi delle colonne:

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

24
Per chiunque cerchi di trovare indici in un database popolato: questa query funziona alla grande, ma cambia la and t.relname like 'test%'riga nella tabella o nelle tabelle che desideri, oppure cancella completamente quella riga per trovare tutti gli indici nel tuo db.
Erik J,

1
Qualcuno potrebbe spiegare cosa relkind='r'significa?
Qwerty,

5
@Qwery, consultare la documentazione per pg_class r = ordinary table, i = index, S = sequence, v = view, c = composite type, t = TOAST table.
cope360,

1
c'è un modo per raccontare anche l'unicità della chiave?
Andrew,

2
per vedere anche l'unicità dell'indice selezionareix.indisunique
Jana

177

PostgreSQL ( pg_indexes ):

SELECT * FROM pg_indexes WHERE tablename = 'mytable';

MySQL ( VISUALIZZA INDICE ):

SHOW INDEX FROM mytable;

3
Questa è la risposta più semplice e la più interessante in termini di risposta alla domanda "La mia colonna è indicizzata?" PostgreSQL: SELECT COUNT(indexname) AS indexcount FROM pg_indexes WHERE tablename='mytablename' AND indexdef LIKE '%mycolumnname%' ;e verifica indexcount>0. mySQL: SHOW INDEX FROM mytablename WHERE Column_name='mycolumnname' ;e verifica che il set di risultati non sia vuoto.
zerobandwidth

2
Sebbene questa sia una risposta molto utile in termini di recupero di informazioni rapide sugli indici, non risponde alla domanda originale poiché la pg_indexesvista non fornisce nomi di colonna. postgresql.org/docs/current/view-pg-indexes.html
akagixxer

146

\d table_namemostra queste informazioni da psql, ma se vuoi ottenere tali informazioni dal database usando SQL, dai un'occhiata a Estrarre informazioni META da PostgreSQL .

Uso tali informazioni nella mia utility per riportare alcune informazioni dallo schema db per confrontare i database PostgreSQL negli ambienti di test e produzione.


Il tuo link sull'estrazione di meta informazioni da Postgres è esattamente quello che stavo cercando! Usando i suggerimenti in questa discussione e alcuni scavi mi sono avvicinato abbastanza alla query che usa in quel post, ma è bello avere tutto così strutturato.
Luke Francl,

1
Sto usando AWS RDS PostgreSQL 9.6.5 e \d tablenon mostra alcun indice, tuttavia \dimostra tutti gli indici.
Hendy Irawan,

@HendyIrawan può apparentemente essere influenzato da altre impostazioni. Come mi chiedo se tu avessi attivato la modalità "solo tuple" (attivata \t). Con "solo tuple" attivo, non ottengo indici da \d, con "solo tuple" spento, lo faccio. Questo è con psql (PostgreSQL) 9.6.15.
JMM,

77

Basta fare: \d table_name

Ma non sono sicuro di cosa intendi che le informazioni sulle colonne non sono lì.

Per esempio:

# \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)

Mostra chiaramente quali colonne sono fornite dell'indice su questa tabella.


Speravo in qualcosa che mi permettesse di fare tutti gli indici su un tavolo ma hai ragione, \d index_nameha le informazioni. Quindi posso cercare gli indici su una tabella, quindi cercare i dettagli. Non mostrando le colonne intendo che ho guardato l'SQL generato dal \d tablenome e non è ovvio per me da dove provenga l'elenco delle colonne. Penso che sia stato analizzato dalla definizione dell'indice, che preferirei non fare.
Luke Francl,

Sto usando AWS RDS PostgreSQL 9.6.5 e \d tablenon mostra alcun indice, tuttavia \dimostra tutti gli indici.
Hendy Irawan,

37

# \di

Il modo più semplice e più breve è \di, che elencherà tutti gli indici nel database corrente.

$ \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)

\diè il "piccolo fratello" del \dcomando che elencherà tutti i rapporti della corrente d atabase. Così \dicertamente significa "mostrami questo d atabase i ndexes".

Digitando \diSverranno elencati tutti gli indici utilizzati a livello di sistema, il che significa che si ottengono anche tutti gli indici 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-- 

Con entrambi questi comandi è possibile aggiungere un +after-it per ottenere ancora più informazioni come la dimensione dello spazio su disco di cui ha bisogno l'indice e una descrizione se disponibile.

$ \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)

In psql puoi trovare facilmente aiuto sulla digitazione dei comandi \?.


2
Ma non mostra i nomi delle colonne su cui vengono creati gli indici. L'indice di chiavi primarie composite ha molte colonne e quelle non sono visibili.
Vignesh Raja,

18

Combinato con altri codici e creato una vista:

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;

12

Alcuni dati di esempio ...

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));

Usa la pg_get_indexdeffunzione:

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)

Semplice ed efficace!
David

Semplicemente fantastico. Sono fortunato ad aver cercato questa risposta.
greatvovan

8

Questo comando mostra anche la vista di variabili, indici e vincoli di tabelle

=# \d table_name;

Esempio:

testannie=# \d dv.l_customer_account;

7

\d tablename mostra i nomi delle colonne per me nella versione 8.3.8.

 "username_idx" UNIQUE, btree (username), tablespace "alldata1"

7

RISULTATO DI QUERY:

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)

DOMANDA:

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;

bello, tuttavia il nome "colonna" per una colonna è una parola riservata. IDEM per schema, dovrebbe usare nome_colonna
parisni il

5

Le informazioni non elaborate sono in pg_index .


Interessante. In particolare indkey: "Questo è un array di valori indnatts che indicano quali colonne di tabella vengono indicizzate da questo indice. Ad esempio, un valore di 1 3 significherebbe che la prima e la terza colonna della tabella compongono la chiave dell'indice. Uno zero in questo array indica che il l'attributo indice corrispondente è un'espressione sopra le colonne della tabella, piuttosto che un semplice riferimento di colonna "
Luke Francl

2

Se vuoi preservare l'ordine delle colonne nell'indice, ecco un modo (molto brutto) per farlo:

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'ordine delle colonne è memorizzato nella colonna pg_index.indkey, quindi l'ho ordinato dagli indici da quell'array.


2

Quando si gioca con gli indici, l'ordine di costruzione delle colonne nell'indice è importante quanto le colonne stesse.

La query seguente elenca tutti gli indici per una determinata tabella e tutte le loro colonne in modo ordinato.

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

2
Perché l'OP dovrebbe "provare questo"? Una buona risposta avrà sempre una spiegazione di ciò che è stato fatto e perché è stato fatto in questo modo, non solo per l'OP ma anche per i futuri visitatori di SO che potrebbero trovare questa domanda e leggere la tua risposta.
Maximilian Ast,

il iper l'ordinalità è molto fluido. Assicura che le colonne siano indicate nell'ordine corretto.
Kbrock,

Questa è stata l'unica risposta che ha funzionato per me. L'ordine delle colonne è fondamentale. (Se non mi credi, cerca tutte le persone con un nome Frank in una rubrica.)
Juraj

1

Prova la query seguente per eseguire il drill-down degli indici richiesti

Interroga come di seguito: l'ho provato personalmente e lo uso spesso.

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;

1

Simile alla risposta accettata ma aver lasciato join su pg_attribute come join normale o query con pg_attribute non fornisce indici che sono come:
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;

buona nota, ma come ottenere informazioni su "lower (column_name") "
pleerock

1

Ecco una funzione che avvolge la risposta di 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;

Uso:

select * from getIndices('<my_table>')

Non ho elencato parti dei miei indici che usano funzioni (es. "Upper (field_name)").
JohnMudd,

0

Che ne dici di una soluzione semplice:

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%'

`


Adoro questa soluzione. Sfortunatamente fallisce con gli indici che hanno clausole where. (o altra parentesi)
kbrock il

Ho cambiato per non saltare le parentesi all'inizio, e non catturare le parentesi nel mezzo, e rilasciare tutto dopo. '^[^\)]*\(([^\)]*)\).*$'
Kbrock,

0

L 'eccellente risposta di @ cope360, convertita per usare la sintassi del join.

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
;

0

Non credo che questa versione esista ancora su questo thread: fornisce sia l'elenco dei nomi delle colonne che il ddl per l'indice.

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;

Ho scoperto che gli indici che utilizzano le funzioni non si collegano ai nomi delle colonne, quindi di tanto in tanto trovi un elenco di indici, ad esempio un nome di colonna quando in realtà è 3.

Esempio:

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

La query restituisce solo "col3" come colonna sull'indice, ma il DDL mostra l'intero set di colonne utilizzate nell'indice.


0

Estendi alla buona risposta di @ Cope360. Per ottenere una determinata tabella (in caso il loro nome sia lo stesso ma uno schema diverso), usando solo la tabella 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;

Spiega: ho il nome della tabella 'tbassettype' in entrambi gli schemi 'dbAsset' e 'dbLegal'. Per ottenere solo una tabella su dbLegal, basta lasciare a.attrelid = il suo OID.


0

Risposta leggermente modificata di @ 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;

Questo mostrerà le colonne dell'indice nell'ordine corretto:

index_name      is_unique  column_name
pk_test         true       c
pk_test         true       a
pk_test         true       b

L'uso di "left join pg_attribute" mostrerà anche indici su colonne calcolate, ovviamente con un nome_colonna 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)

0

La risposta accettata da @ cope360 è buona, ma volevo qualcosa di più simile a Oracle DBA_IND_COLUMNS, ALL_IND_COLUMNS e USER_IND_COLUMNS (ad esempio, riporta lo schema di tabella / indice e la posizione dell'indice in un indice a più colonne), quindi ho adattato l'accettato rispondere a questo:

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
;

Questo dà un output come:

 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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.