Lista kolumn z indeksami w PostgreSQL

233

Chciałbym uzyskać kolumny, w których znajduje się indeks w PostgreSQL.

W MySQL możesz używać SHOW INDEXES FOR tablei przeglądać Column_namekolumnę.

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

Czy coś takiego istnieje dla PostgreSQL?

Próbowałem \dw psqlwierszu polecenia (z -Eopcją pokazania SQL), ale nie wyświetla informacji, których szukam.

Aktualizacja: Dziękujemy wszystkim, którzy dodali swoje odpowiedzi. cope360 dał mi dokładnie to, czego szukałem, ale kilka osób zaglądało z bardzo przydatnymi linkami. Do wykorzystania w przyszłości zajrzyj do dokumentacji pg_index (przez Milena A. Radeva ) i bardzo przydatnego artykułu Ekstrakcja informacji META z PostgreSQL (przez Michała Niklasa ).

Luke Francl
źródło
Wyjaśnij: Chcesz, aby Twój program mógł w czasie wykonywania ustalić, które kolumny są indeksowane, prawda? W przeciwieństwie do ciebie znajomość programowania.
Wayne Conrad
Tak, poprawnie. Idealnie chciałbym, aby instrukcja SQL zawierała TYLKO kolumny, w których znajduje się indeks. Ale wiem, że PostgreSQL jest bardziej skomplikowany niż MySQL i indeks może być na funkcji itp.
Luke Francl

Odpowiedzi:

261

Utwórz dane testowe ...

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

Lista indeksów i indeksowanych kolumn:

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

Zwinąć nazwy kolumn:

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
źródło
24
Dla każdego, kto próbuje znaleźć indeksy w zapełnionej bazie danych: to zapytanie działa świetnie, ale zmień and t.relname like 'test%'wiersz na żądane tabele lub całkowicie usuń ten wiersz, aby znaleźć wszystkie indeksy w bazie danych.
Erik J
1
Czy ktoś mógłby wyjaśnić, co relkind='r'to znaczy?
Qwerty
5
@ Bardzo często, patrz dokumentacja pg_class r = ordinary table, i = index, S = sequence, v = view, c = composite type, t = TOAST table.
cope360
1
czy istnieje sposób, aby powiedzieć także o wyjątkowości klucza?
Andrew
2
aby zobaczyć unikalność indeksu, wybierz takżeix.indisunique
Jana
177

PostgreSQL ( pg_indexes ):

SELECT * FROM pg_indexes WHERE tablename = 'mytable';

MySQL ( POKAŻ INDEKS ):

SHOW INDEX FROM mytable;
Valentin Podkamennyi
źródło
3
To jest najprostsza i najciekawsza odpowiedź na pytanie „Czy moja kolumna jest zaindeksowana?” PostgreSQL: SELECT COUNT(indexname) AS indexcount FROM pg_indexes WHERE tablename='mytablename' AND indexdef LIKE '%mycolumnname%' ;i zweryfikuj indexcount>0. mySQL: SHOW INDEX FROM mytablename WHERE Column_name='mycolumnname' ;i sprawdź, czy zestaw wyników nie jest pusty.
zerobandwidth
2
Chociaż jest to bardzo przydatna odpowiedź w zakresie wyszukiwania szybkich informacji o indeksach, nie odpowiada na pierwotne pytanie, ponieważ pg_indexeswidok nie zawiera nazw kolumn. postgresql.org/docs/current/view-pg-indexes.html
akagixxer
146

\d table_namepokazuje te informacje psql, ale jeśli chcesz uzyskać takie informacje z bazy danych za pomocą SQL, spójrz na Wydobywanie informacji META z PostgreSQL .

Używam takich informacji w moim narzędziu do zgłaszania niektórych informacji ze schematu db do porównywania baz danych PostgreSQL w środowisku testowym i produkcyjnym.

Michał Niklas
źródło
Twój link do wydobywania meta informacji z Postgres jest dokładnie tym, czego szukałem! Korzystając ze wskazówek w tym wątku i trochę kopiąc, zbliżyłem się do zapytania, którego używa w tym poście, ale miło jest mieć to wszystko ułożone w ten sposób.
Luke Francl
1
Korzystam z AWS RDS PostgreSQL 9.6.5 i \d tablenie wyświetla żadnych indeksów, ale \dipokazuje wszystkie indeksy.
Hendy Irawan
@HendyIrawan może najwyraźniej mieć wpływ na inne ustawienia. Zastanawiam się, czy miałeś włączony tryb „krotek” (przełączany przez \t). Przy włączonej opcji „tylko krotki” nie otrzymuję indeksów \d, a przy opcji „tylko krotki” wyłączone. Dotyczy to psql (PostgreSQL) 9.6.15.
JMM
77

Po prostu zrób: \d table_name

Ale nie jestem pewien, co masz na myśli, że nie ma tam informacji o kolumnach.

Na przykład:

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

Wyraźnie pokazuje, które kolumny mają indeks w tej tabeli.

Shilovk
źródło
Miałem nadzieję na coś, co pozwoli mi wykonać wszystkie indeksy na stole, ale masz rację, \d index_namema informacje. Więc mogę sprawdzić indeksy w tabeli, a następnie sprawdzić szczegóły. Nie pokazując kolumn mam na myśli, że spojrzałem na SQL wygenerowany według \d tablenazwy i nie jest dla mnie oczywiste, skąd pochodzi lista kolumn. Myślę, że jest on analizowany na podstawie definicji indeksu, czego wolałbym nie robić.
Luke Francl
Korzystam z AWS RDS PostgreSQL 9.6.5 i \d tablenie wyświetla żadnych indeksów, ale \dipokazuje wszystkie indeksy.
Hendy Irawan
37

# \di

Najłatwiejszym i najkrótszym sposobem jest \diwyświetlenie wszystkich indeksów w bieżącej bazie danych.

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

\dijest „mały brat” z \dpolecenia, które wyświetli wszystkie kontakty bieżącego d atabase. Zatem \diz pewnością stać na „pokaż mi to d atabases i ndexes”.

Wpisanie \diSspowoduje wyświetlenie wszystkich indeksów używanych w całym systemie, co oznacza, że ​​otrzymasz także wszystkie indeksy 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-- 

Za pomocą obu tych poleceń możesz dodać +po nim, aby uzyskać jeszcze więcej informacji, takich jak rozmiar potrzebnego miejsca na dysku, a także opis, jeśli jest dostępny.

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

W psql można łatwo znaleźć pomoc dotyczącą pisania poleceń \?.

sebisnow
źródło
2
Ale nie pokazuje nazw kolumn, na których tworzone są indeksy. Złożony indeks kluczy podstawowych ma wiele kolumn i nie można ich zobaczyć.
Vignesh Raja,
18

W połączeniu z innymi kodami i stworzył widok:

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
źródło
12

Niektóre przykładowe dane ...

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

Użyj pg_get_indexdeffunkcji:

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
źródło
Prosty i skuteczny!
David
Po prostu niesamowite. Mam szczęście, że przewinąłem tę odpowiedź.
greatvovan
8

To polecenie pokazuje także widok zmiennych tabeli, indeksów i ograniczeń

=# \d table_name;

Przykład:

testannie=# \d dv.l_customer_account;
aryjski
źródło
7

\d tablename pokazuje mi nazwy kolumn w wersji 8.3.8.

 "username_idx" UNIQUE, btree (username), tablespace "alldata1"
Corey
źródło
7

WYNIK ZAPYTANIA:

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)

PYTANIE:

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
źródło
fajnie, jednak nazwa kolumny to słowo zastrzeżone. IDEM dla schematu, należy użyć nazwa_kolumny
paryż
5

Nieprzetworzone informacje znajdują się w pg_index .

Milen A. Radev
źródło
Ciekawy. W szczególności indkey: „Jest to tablica wartości indnatts wskazujących, które kolumny tabeli indeksuje ten indeks. Na przykład wartość 1 3 oznaczałaby, że pierwsza i trzecia kolumna tabeli tworzą klucz indeksu. Zero w tej tablicy wskazuje, że odpowiadający atrybut indeksu jest wyrażeniem nad kolumnami tabeli, a nie prostym odniesieniem do kolumny ”
Luke Francl
2

Jeśli chcesz zachować kolejność kolumn w indeksie, oto (bardzo brzydki) sposób:

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

kolejność kolumn jest przechowywana w kolumnie pg_index.indkey, więc uporządkowałem według indeksów z tej tablicy.

David Willis
źródło
2

Podczas zabawy z indeksami kolejność budowania kolumn w indeksie jest równie ważna jak same kolumny.

Poniższe zapytanie zawiera listę wszystkich indeksów dla danej tabeli i wszystkich ich kolumn w posortowany sposób.

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
użytkownik6654165
źródło
2
Dlaczego PO powinien „wypróbować to”? Dobra odpowiedź zawsze będzie wyjaśnienie, co się stało i dlaczego to było zrobione w ten sposób, nie tylko dla PO, ale dla przyszłych odwiedzających, dzięki czemu mogą znaleźć na to pytanie i czytać swoją odpowiedź.
Maximilian Ast
idla ordinality jest bardzo śliski. Zapewnia to, że kolumny są podane we właściwej kolejności.
kbrock
To była jedyna odpowiedź, która zadziałała dla mnie. Kolejność kolumn jest krytyczna. (Jeśli mi nie wierzysz, poszukaj wszystkich osób o nazwisku Frank w książce telefonicznej.)
Juraj,
1

Wypróbuj poniższe zapytanie, aby przejść do wymaganych indeksów

Zapytanie jak poniżej - próbowałem tego osobiście i często go używam.

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
źródło
1

Podobne do zaakceptowanej odpowiedzi, ale pozostawienie dołączenia do pg_attribute jako normalnego sprzężenia lub zapytania z pg_attribute nie daje wskaźników, które są jak:
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
źródło
dobra uwaga, ale jak uzyskać informacje o tym „niższym (nazwa_kolumny”) ”
pleerock
1

Oto funkcja, która otacza odpowiedź 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;

Stosowanie:

select * from getIndices('<my_table>')
Chribsen
źródło
Nie wymieniono części moich indeksów, które używają funkcji (np. „Górna (nazwa_pola)”).
JohnMudd
0

A może proste rozwiązanie:

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
źródło
Uwielbiam to rozwiązanie. Niestety zawodzi w przypadku indeksów zawierających klauzule where. (lub inny nawias)
kbrock
Zmieniłem, aby nie pomijać parenów na początku, nie przechwytywać parenów na środku i porzucić wszystko. '^[^\)]*\(([^\)]*)\).*$'
kbrock
0

Doskonała odpowiedź @ cope360, przekonwertowana na składnię łączenia.

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
źródło
0

Nie sądzę, aby ta wersja istniała jeszcze w tym wątku: zawiera ona zarówno listę nazw kolumn, jak i ddl dla indeksu.

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;

Odkryłem, że indeksy korzystające z funkcji nie łączą się z nazwami kolumn, więc od czasu do czasu można znaleźć listę indeksów, np. Nazwę jednej kolumny, gdy w rzeczywistości używana jest 3.

Przykład:

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

Zapytanie zwraca tylko „col3” jako kolumnę w indeksie, ale DDL pokazuje pełny zestaw kolumn używanych w indeksie.

datico
źródło
0

Rozszerz na dobrą odpowiedź na @ Cope360. Aby uzyskać dla określonej tabeli (należy dodać, że ma taką samą nazwę, ale inny schemat), wystarczy użyć OID tabeli.

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;

Wyjaśnij: Mam nazwę tabeli „tbassettype” zarówno w schemacie „dbAsset”, jak i „dbLegal”. Aby uzyskać tylko tabelę na dbLegal, po prostu pozwól a.attrelid = jego OID.

Wutikrai
źródło
0

Trochę zmodyfikowana odpowiedź @ 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;

Spowoduje to wyświetlenie kolumn indeksu we właściwej kolejności:

index_name      is_unique  column_name
pk_test         true       c
pk_test         true       a
pk_test         true       b
Nikita Ryanov
źródło
Użycie „lewego złączenia pg_attribute” spowoduje także wyświetlenie indeksów w kolumnach obliczeniowych, oczywiście z NULL nazwa_kolumny.
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
źródło
0

Odpowiedź zaakceptowana przez @ cope360 jest dobra, ale chciałem czegoś bardziej jak Oracle DBA_IND_COLUMNS, ALL_IND_COLUMNS i USER_IND_COLUMNS (np. Raportuje schemat tabeli / indeksu i pozycję indeksu w indeksie wielokolumnowym), więc dostosowałem zaakceptowany odpowiedz na to:

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
;

Daje to wynik taki jak:

 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
źródło