Daftar kolom dengan indeks di PostgreSQL

233

Saya ingin mendapatkan kolom yang indeksnya ada di PostgreSQL.

Di MySQL Anda dapat menggunakan SHOW INDEXES FOR tabledan melihat Column_namekolom.

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

Apakah ada yang seperti ini untuk PostgreSQL?

Saya sudah mencoba \ddi psqlcommand prompt (dengan -Epilihan untuk menampilkan SQL) tetapi tidak menunjukkan informasi yang saya cari.

Pembaruan: Terima kasih kepada semua orang yang menambahkan jawaban mereka. cope360 memberi saya apa yang saya cari, tetapi beberapa orang menimpali dengan tautan yang sangat berguna. Untuk referensi di masa mendatang, lihat dokumentasi untuk pg_index (via Milen A. Radev ) dan artikel yang sangat berguna Mengekstraksi informasi META dari PostgreSQL (via Michał Niklas ).

Luke Francl
sumber
Hanya untuk mengklarifikasi: Anda ingin program Anda dapat mengetahui, saat runtime, kolom mana yang diindeks, kan? Berbeda dengan Anda yang mengetahui pemrograman.
Wayne Conrad
Ya benar. Idealnya saya ingin pernyataan SQL yang HANYA daftar kolom yang indeksnya aktif. Tapi saya tahu PostgreSQL lebih rumit dari MySQL dan indeksnya bisa pada fungsi, dll.
Luke Francl

Jawaban:

261

Buat beberapa data uji ...

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

Daftar indeks dan kolom yang diindeks:

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

Gulung nama kolom:

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
sumber
24
Bagi siapa pun yang mencoba menemukan indeks dalam database terpopulasi: kueri ini berfungsi dengan baik, tetapi ubah and t.relname like 'test%'baris ke tabel yang Anda inginkan, atau hapus baris itu sepenuhnya untuk menemukan semua indeks di db Anda.
Erik J
1
Bisakah seseorang menjelaskan apa relkind='r'artinya?
Qwerty
5
@Qwery, lihat dokumentasi untuk pg_class r = ordinary table, i = index, S = sequence, v = view, c = composite type, t = TOAST table.
cope360
1
apakah ada cara untuk menceritakan tentang keunikan kunci?
Andrew
2
untuk melihat keunikan indeks juga pilihix.indisunique
Jana
177

PostgreSQL ( pg_indexes ):

SELECT * FROM pg_indexes WHERE tablename = 'mytable';

MySQL ( TAMPILKAN INDEKS ):

SHOW INDEX FROM mytable;
Valentin Podkamennyi
sumber
3
Ini adalah jawaban yang paling mudah, dan yang paling menarik dalam menjawab pertanyaan "Apakah kolom saya diindeks?" PostgreSQL: SELECT COUNT(indexname) AS indexcount FROM pg_indexes WHERE tablename='mytablename' AND indexdef LIKE '%mycolumnname%' ;dan verifikasi indexcount>0. mySQL: SHOW INDEX FROM mytablename WHERE Column_name='mycolumnname' ;dan verifikasi set hasil tidak kosong.
zerobandwidth
2
Meskipun ini adalah jawaban yang sangat berguna dalam hal mengambil informasi cepat tentang indeks, ini tidak menjawab pertanyaan awal karena pg_indexestampilan tidak memberikan nama kolom. postgresql.org/docs/current/view-pg-indexes.html
akagixxer
146

\d table_namemenunjukkan informasi ini dari psql, tetapi jika Anda ingin mendapatkan informasi tersebut dari database menggunakan SQL maka lihatlah Mengekstrak informasi META dari PostgreSQL .

Saya menggunakan info tersebut di utilitas saya untuk melaporkan beberapa info dari skema db untuk membandingkan database PostgreSQL dalam lingkungan pengujian dan produksi.

Michał Niklas
sumber
Tautan Anda untuk mengekstraksi informasi meta dari Postgres persis seperti yang saya cari! Dengan menggunakan tips di utas ini dan beberapa penggalian saya cukup dekat dengan permintaan yang dia gunakan di posting itu, tapi senang semuanya ditata seperti itu.
Luke Francl
1
Saya menggunakan AWS RDS PostgreSQL 9.6.5 dan \d tabletidak menampilkan indeks apa pun, namun \dimenampilkan semua indeks.
Hendy Irawan
@HendyIrawan tampaknya dapat dipengaruhi oleh pengaturan lain. Seperti saya ingin tahu apakah Anda memiliki "tuple only" mode on (toggle by \t). Dengan "tuple only" aktif, saya tidak mendapatkan indeks dari \d, dengan "tuple only" off, saya lakukan. Ini dengan psql (PostgreSQL) 9.6.15.
JMM
77

Kerjakan saja: \d table_name

Tetapi saya tidak yakin apa maksud Anda bahwa informasi tentang kolom tidak ada.

Sebagai contoh:

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

Ini jelas menunjukkan kolom mana yang diberikan indeks pada tabel ini.

shilovk
sumber
Saya berharap sesuatu yang akan memungkinkan saya melakukan semua indeks di atas meja tetapi Anda benar, \d index_namememang memiliki informasi. Jadi saya bisa melihat indeks di atas meja, lalu mencari detailnya. Dengan tidak menunjukkan kolom yang saya maksud, saya melihat SQL yang dihasilkan oleh \d tablenama dan tidak jelas bagi saya dari mana daftar kolom berasal. Saya pikir ini sedang diurai keluar dari definisi indeks, yang saya lebih suka tidak melakukannya.
Luke Francl
Saya menggunakan AWS RDS PostgreSQL 9.6.5 dan \d tabletidak menampilkan indeks apa pun, namun \dimenampilkan semua indeks.
Hendy Irawan
37

# \di

Cara termudah dan terpendek adalah \di, yang akan mendaftar semua indeks dalam database saat ini.

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

\diadalah "saudara kecil" dari \dperintah yang akan daftar semua hubungan arus d atabase. Jadi \ditentu berdiri untuk "menunjukkan ini d atabases i ndexes".

Mengetik \diSakan mencantumkan semua indeks yang digunakan di seluruh sistem, yang berarti Anda mendapatkan semua indeks pg_catalog juga.

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

Dengan kedua perintah ini, Anda dapat menambahkan +setelahnya untuk mendapatkan informasi lebih lanjut seperti ukuran ruang disk yang diperlukan indeks dan deskripsi jika tersedia.

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

Di psql Anda dapat dengan mudah menemukan bantuan tentang mengetik perintah \?.

sebisnow
sumber
2
Tapi itu tidak menunjukkan nama kolom tempat indeks dibuat. Indeks kunci primer komposit memiliki banyak kolom dan yang tidak dapat dilihat.
Vignesh Raja
18

Dikombinasikan dengan kode orang lain dan membuat tampilan:

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
sumber
12

Beberapa data sampel ...

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

Gunakan pg_get_indexdeffungsi:

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
sumber
Sederhana dan efektif!
David
Menakjubkan. Saya beruntung saya telah menggulir ke jawaban ini.
greatvovan
8

Perintah ini juga menampilkan tampilan variabel tabel, indeks, dan batasan

=# \d table_name;

Contoh:

testannie=# \d dv.l_customer_account;
Arya
sumber
7

\d tablename menunjukkan nama kolom untuk saya di versi 8.3.8.

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

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

PERTANYAAN:

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
sumber
bagus, namun nama "kolom" untuk sebuah kolom adalah kata yang dipesan. IDEM untuk skema, harus menggunakan nama_kolom
parisni
5

Info mentah ada di pg_index .

Milen A. Radev
sumber
Menarik. Khususnya indkey: "Ini adalah array nilai indnatts yang menunjukkan kolom tabel mana yang indeks indeks ini. Misalnya nilai 1 3 akan berarti bahwa kolom tabel pertama dan ketiga membentuk kunci indeks. Nol dalam array ini menunjukkan bahwa atribut indeks yang sesuai adalah ekspresi di atas kolom tabel, daripada referensi kolom sederhana "
Luke Francl
2

Jika Anda ingin mempertahankan urutan kolom dalam indeks, berikut ini cara (yang sangat jelek) untuk melakukannya:

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

urutan kolom disimpan di kolom pg_index.indkey, jadi saya memesan oleh subskrip dari array itu.

David Willis
sumber
2

Saat bermain-main dengan indeks urutan kolom yang dibangun dalam indeks sama pentingnya dengan kolom itu sendiri.

Kueri berikut mencantumkan semua indeks untuk tabel yang diberikan dan semua kolomnya dengan cara yang diurutkan.

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
pengguna6654165
sumber
2
Mengapa OP "coba ini"? Sebuah jawaban yang baik akan selalu memiliki penjelasan tentang apa yang dilakukan dan mengapa hal itu dilakukan dengan cara itu, tidak hanya untuk OP tapi untuk masa depan pengunjung ke SO yang mungkin menemukan pertanyaan ini dan membaca jawaban Anda.
Maximilian Ast
yang iuntuk Ordinality sangat licin. Ini memastikan kolom dinyatakan dalam urutan yang benar.
kbrock
Ini adalah satu-satunya jawaban yang berhasil untuk saya. Urutan kolom sangat penting. (Jika Anda tidak percaya kepada saya, carilah semua orang dengan nama depan, Frank, dalam buku telepon.)
Juraj
1

Silakan coba kueri di bawah ini untuk menelusuri indeks yang diperlukan

Kueri seperti di bawah ini - saya telah mencoba ini secara pribadi dan sering menggunakannya.

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
sumber
1

Mirip dengan jawaban yang diterima tetapi setelah kiri bergabung di pg_attribute sebagai bergabung normal atau permintaan dengan pg_attribute tidak memberikan indeks yang seperti:
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
sumber
catatan yang baik, tetapi bagaimana cara mendapatkan informasi tentang "lower (column_name") "
pleerock
1

Inilah fungsi yang membungkus jawaban 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;

Pemakaian:

select * from getIndices('<my_table>')
anak-anak
sumber
Tidak mencantumkan bagian indeks saya yang menggunakan fungsi (mis. "Upper (field_name)").
JohnMudd
0

Bagaimana dengan solusi sederhana:

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
sumber
Cintai solusi ini. Sayangnya gagal dengan indeks yang memiliki klausa mana. (atau tanda kurung lainnya)
kbrock
Saya berubah untuk tidak melewatkan parens di awal, dan tidak menangkap parens di tengah, dan meninggalkan semuanya setelah itu. '^[^\)]*\(([^\)]*)\).*$'
kbrock
0

@ jawaban luar biasa cope360, dikonversi untuk menggunakan sintaks bergabung.

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
sumber
0

Saya rasa versi ini belum ada di utas ini: ia menyediakan daftar nama kolom beserta ddl untuk indeks.

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;

Saya menemukan bahwa indeks menggunakan fungsi tidak menautkan ke nama kolom, jadi kadang-kadang Anda menemukan daftar indeks misalnya satu nama kolom padahal sebenarnya menggunakan 3.

Contoh:

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

Kueri mengembalikan hanya 'col3' sebagai kolom pada indeks, tetapi DDL menunjukkan set lengkap kolom yang digunakan dalam indeks.

Datico
sumber
0

Perluas jawaban yang baik dari @ Cope360. Untuk mendapatkan tabel tertentu (gunakan nama tabel yang sama tetapi skema yang berbeda), cukup gunakan tabel 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;

Jelaskan: Saya memiliki nama tabel 'tbassettype' di kedua skema 'dbAsset' dan 'dbLegal'. Untuk mendapatkan hanya tabel di dbLegal, biarkan a.attrelid = OID-nya.

Wutikrai
sumber
0

Jawaban sedikit dimodifikasi dari @ 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;

Ini akan menampilkan kolom indeks dalam urutan yang benar:

index_name      is_unique  column_name
pk_test         true       c
pk_test         true       a
pk_test         true       b
Nikita Ryanov
sumber
Menggunakan "gabung kiri pg_attribute" juga akan menampilkan indeks pada kolom yang dihitung, tentu saja dengan NULL nama_kolom.
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
sumber
0

Jawaban yang diterima oleh @ cope360 baik, tetapi saya ingin sesuatu yang sedikit lebih seperti Oracle DBA_IND_COLUMNS, ALL_IND_COLUMNS, dan USER_IND_COLUMNS (misalnya, melaporkan skema tabel / indeks dan posisi indeks dalam indeks multikolom), jadi saya menyesuaikan penerimaan dalam indeks multikolom), jadi saya menyesuaikan yang diterima jawab ini:

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
;

Ini menghasilkan output seperti:

 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
sumber