Spread chunk indexes across tablespaces like chunks

Currently, chunk indexes are always created in the tablespace of the
index on the main table (which could be none/default one), even if the
chunks themselves are created in different tablespaces. This is
problematic in a multi-disk setting where each disk is a separate
tablespace where chunks are placed. The chunk indexes might exhaust
the space on the common (often default tablespace) which might not
have a lot of disk space. This also prohibits the database, including
index storage to grow by adding new tablespaces.

Instead, chunk indexes are now created in the "next" tablespace after
that of their chunks to both spread indexes across tablespaces and
avoid colocating indexes with their chunks (for I/O throughput
reasons). To optionally avoid this spreading, one can pin chunk
indexes to a specific tablespace by setting an explicit tablespace on
a main table index.
This commit is contained in:
Erik Nordström 2018-01-15 11:48:41 +01:00 committed by Erik Nordström
parent e85721a8ed
commit d135256ed7
12 changed files with 193 additions and 78 deletions

View File

@ -400,7 +400,7 @@ chunk_create_table(Chunk *chunk, Hypertable *ht)
.type = T_CreateStmt,
.relation = makeRangeVar(NameStr(chunk->fd.schema_name), NameStr(chunk->fd.table_name), 0),
.inhRelations = list_make1(makeRangeVar(NameStr(ht->fd.schema_name), NameStr(ht->fd.table_name), 0)),
.tablespacename = hypertable_select_tablespace(ht, chunk),
.tablespacename = hypertable_select_tablespace_name(ht, chunk),
.options = get_reloptions(ht->main_table_relid),
};
Oid uid,

View File

@ -195,6 +195,35 @@ chunk_adjust_attnos(IndexInfo *ii, Relation htrel, Relation idxrel, Relation chu
chunk_adjust_expr_attnos(ii, htrel, idxrel, chunkrel);
}
#define CHUNK_INDEX_TABLESPACE_OFFSET 1
/*
* Pick a chunk index's tablespace at an offset from the chunk's tablespace in
* order to avoid colocating chunks and their indexes in the same tablespace.
* This hopefully leads to more I/O parallelism.
*/
static Oid
chunk_index_select_tablespace(Relation htrel, Relation chunkrel)
{
Cache *hcache = hypertable_cache_pin();
Hypertable *ht = hypertable_cache_get_entry(hcache, htrel->rd_id);
Tablespace *tspc;
Oid tablespace_oid = InvalidOid;
Assert(ht != NULL);
tspc = hypertable_get_tablespace_at_offset_from(ht, chunkrel->rd_rel->reltablespace,
CHUNK_INDEX_TABLESPACE_OFFSET);
if (NULL != tspc)
tablespace_oid = tspc->tablespace_oid;
cache_release(hcache);
return tablespace_oid;
}
/*
* Create a chunk index based on the configuration of the "parent" index.
*/
@ -213,6 +242,7 @@ chunk_relation_index_create(Relation htrel,
Datum indclass;
oidvector *indclassoid;
List *colnames = create_index_colnames(template_indexrel);
Oid tablespace = InvalidOid;
/*
* Convert the IndexInfo's attnos to match the chunk instead of the
@ -239,6 +269,15 @@ chunk_relation_index_create(Relation htrel,
get_rel_name(RelationGetRelid(template_indexrel)),
get_rel_namespace(RelationGetRelid(chunkrel)));
/*
* Determine the index's tablespace. Use the main index's tablespace, or,
* if not set, select one at an offset from the chunk's tablespace.
*/
if (OidIsValid(template_indexrel->rd_rel->reltablespace))
tablespace = template_indexrel->rd_rel->reltablespace;
else
tablespace = chunk_index_select_tablespace(htrel, chunkrel);
chunk_indexrelid = index_create(chunkrel,
indexname,
InvalidOid,
@ -246,7 +285,7 @@ chunk_relation_index_create(Relation htrel,
indexinfo,
colnames,
template_indexrel->rd_rel->relam,
template_indexrel->rd_rel->reltablespace,
tablespace,
template_indexrel->rd_indcollation,
indclassoid->values,
template_indexrel->rd_indoption,

View File

@ -282,7 +282,7 @@ hypertable_has_tablespace(Hypertable *ht, Oid tspc_oid)
* chunks in the same closed (space) dimension. This ensures chunks in the same
* "space" partition will live on the same disk.
*/
char *
Tablespace *
hypertable_select_tablespace(Hypertable *ht, Chunk *chunk)
{
Dimension *dim;
@ -318,7 +318,39 @@ hypertable_select_tablespace(Hypertable *ht, Chunk *chunk)
Assert(i >= 0);
/* Use the index of the slice to find the tablespace */
return NameStr(tspcs->tablespaces[i % tspcs->num_tablespaces].fd.tablespace_name);
return &tspcs->tablespaces[i % tspcs->num_tablespaces];
}
char *
hypertable_select_tablespace_name(Hypertable *ht, Chunk *chunk)
{
Tablespace *tspc = hypertable_select_tablespace(ht, chunk);
if (NULL == tspc)
return NULL;
return NameStr(tspc->fd.tablespace_name);
}
/*
* Get the tablespace at an offset from the given tablespace.
*/
Tablespace *
hypertable_get_tablespace_at_offset_from(Hypertable *ht, Oid tablespace_oid, int16 offset)
{
Tablespaces *tspcs = tablespace_scan(ht->fd.id);
int i = 0;
if (NULL == tspcs || tspcs->num_tablespaces == 0)
return NULL;
for (i = 0; i < tspcs->num_tablespaces; i++)
{
if (tablespace_oid == tspcs->tablespaces[i].tablespace_oid)
return &tspcs->tablespaces[(i + offset) % tspcs->num_tablespaces];
}
return NULL;
}
static inline Oid

View File

@ -30,6 +30,8 @@ extern Chunk *hypertable_get_chunk(Hypertable *h, Point *point);
extern Oid hypertable_relid(RangeVar *rv);
extern bool is_hypertable(Oid relid);
extern bool hypertable_has_tablespace(Hypertable *ht, Oid tspc_oid);
extern char *hypertable_select_tablespace(Hypertable *ht, Chunk *chunk);
extern Tablespace *hypertable_select_tablespace(Hypertable *ht, Chunk *chunk);
extern char *hypertable_select_tablespace_name(Hypertable *ht, Chunk *chunk);
extern Tablespace *hypertable_get_tablespace_at_offset_from(Hypertable *ht, Oid tablespace_oid, int16 offset);
#endif /* TIMESCALEDB_HYPERTABLE_H */

View File

@ -318,15 +318,15 @@ SET timezone = '+1';
INSERT INTO PUBLIC.drop_chunk_test_ts VALUES(now()-INTERVAL '5 minutes', 1.0, 'dev1');
INSERT INTO PUBLIC.drop_chunk_test_tstz VALUES(now()-INTERVAL '5 minutes', 1.0, 'dev1');
SELECT * FROM test.show_subtables('drop_chunk_test_ts');
Child
-----------------------------------------
_timescaledb_internal._hyper_4_19_chunk
Child | Tablespace
-----------------------------------------+------------
_timescaledb_internal._hyper_4_19_chunk |
(1 row)
SELECT * FROM test.show_subtables('drop_chunk_test_tstz');
Child
-----------------------------------------
_timescaledb_internal._hyper_5_20_chunk
Child | Tablespace
-----------------------------------------+------------
_timescaledb_internal._hyper_5_20_chunk |
(1 row)
BEGIN;
@ -337,8 +337,8 @@ BEGIN;
(1 row)
SELECT * FROM test.show_subtables('drop_chunk_test_ts');
Child
-------
Child | Tablespace
-------+------------
(0 rows)
SELECT drop_chunks(interval '1 minute', 'drop_chunk_test_tstz');
@ -348,8 +348,8 @@ BEGIN;
(1 row)
SELECT * FROM test.show_subtables('drop_chunk_test_tstz');
Child
-------
Child | Tablespace
-------+------------
(0 rows)
ROLLBACK;
@ -361,8 +361,8 @@ BEGIN;
(1 row)
SELECT * FROM test.show_subtables('drop_chunk_test_ts');
Child
-------
Child | Tablespace
-------+------------
(0 rows)
SELECT drop_chunks(now()-interval '1 minute', 'drop_chunk_test_tstz');
@ -372,8 +372,8 @@ BEGIN;
(1 row)
SELECT * FROM test.show_subtables('drop_chunk_test_tstz');
Child
-------
Child | Tablespace
-------+------------
(0 rows)
ROLLBACK;
@ -405,8 +405,8 @@ BEGIN;
(1 row)
SELECT * FROM test.show_subtables('drop_chunk_test_date');
Child
-------
Child | Tablespace
-------+------------
(0 rows)
ROLLBACK;
@ -418,8 +418,8 @@ BEGIN;
(1 row)
SELECT * FROM test.show_subtables('drop_chunk_test_date');
Child
-------
Child | Tablespace
-------+------------
(0 rows)
ROLLBACK;

View File

@ -398,7 +398,7 @@ SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
----------------------------------------+-------------------------------------------------------------------+--------------------+--------+---------+-----------+-------------
_timescaledb_internal._hyper_5_5_chunk | _timescaledb_internal._hyper_5_5_chunk_index_test_time_idx | {time,temp,device} | f | f | f | tablespace1
_timescaledb_internal._hyper_5_5_chunk | _timescaledb_internal._hyper_5_5_chunk_index_test_time_device_idx | {time,temp,device} | f | f | f | tablespace2
_timescaledb_internal._hyper_5_5_chunk | _timescaledb_internal._hyper_5_5_chunk_index_test_device_idx | {time,temp,device} | f | f | f |
_timescaledb_internal._hyper_5_5_chunk | _timescaledb_internal._hyper_5_5_chunk_index_test_device_idx | {time,temp,device} | f | f | f | tablespace1
(3 rows)
-- Creating a new index should propagate to existing chunks, including
@ -418,7 +418,7 @@ SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
----------------------------------------+-------------------------------------------------------------------+--------------------+--------+---------+-----------+-------------
_timescaledb_internal._hyper_5_5_chunk | _timescaledb_internal._hyper_5_5_chunk_index_test_time_idx | {time,temp,device} | f | f | f | tablespace1
_timescaledb_internal._hyper_5_5_chunk | _timescaledb_internal._hyper_5_5_chunk_index_test_time_device_idx | {time,temp,device} | f | f | f | tablespace2
_timescaledb_internal._hyper_5_5_chunk | _timescaledb_internal._hyper_5_5_chunk_index_test_device_idx | {time,temp,device} | f | f | f |
_timescaledb_internal._hyper_5_5_chunk | _timescaledb_internal._hyper_5_5_chunk_index_test_device_idx | {time,temp,device} | f | f | f | tablespace1
_timescaledb_internal._hyper_5_5_chunk | _timescaledb_internal._hyper_5_5_chunk_time_temp_idx | {time,temp,device} | f | f | f | tablespace2
(4 rows)

View File

@ -21,13 +21,13 @@ SELECT * FROM test.show_columns('reindex_test');
(2 rows)
SELECT * FROM test.show_subtables('reindex_test');
Child
----------------------------------------
_timescaledb_internal._hyper_1_1_chunk
_timescaledb_internal._hyper_1_2_chunk
_timescaledb_internal._hyper_1_3_chunk
_timescaledb_internal._hyper_1_4_chunk
_timescaledb_internal._hyper_1_5_chunk
Child | Tablespace
----------------------------------------+------------
_timescaledb_internal._hyper_1_1_chunk |
_timescaledb_internal._hyper_1_2_chunk |
_timescaledb_internal._hyper_1_3_chunk |
_timescaledb_internal._hyper_1_4_chunk |
_timescaledb_internal._hyper_1_5_chunk |
(5 rows)
-- show reindexing

View File

@ -122,10 +122,10 @@ INSERT INTO "int_part" VALUES('2017-01-20T09:00:01', 1, 22.5);
INSERT INTO "int_part" VALUES('2017-01-20T09:00:01', 2, 22.5);
--check that there are two chunks
SELECT * FROM test.show_subtables('int_part');
Child
----------------------------------------
_timescaledb_internal._hyper_2_5_chunk
_timescaledb_internal._hyper_2_6_chunk
Child | Tablespace
----------------------------------------+------------
_timescaledb_internal._hyper_2_5_chunk |
_timescaledb_internal._hyper_2_6_chunk |
(2 rows)
SELECT * FROM "int_part" WHERE object_id = 1;

View File

@ -77,25 +77,33 @@ SELECT * FROM show_tablespaces('tspace_2dim');
--insert into another chunk
INSERT INTO tspace_2dim VALUES ('2017-01-20T09:00:01', 24.3, 'brown');
SELECT relname, spcname FROM pg_class c
INNER JOIN pg_tablespace t ON (c.reltablespace = t.oid)
INNER JOIN _timescaledb_catalog.chunk ch ON (ch.table_name = c.relname);
relname | spcname
------------------+-------------
_hyper_1_1_chunk | tablespace1
_hyper_1_2_chunk | tablespace2
SELECT * FROM test.show_subtables('tspace_2dim');
Child | Tablespace
----------------------------------------+-------------
_timescaledb_internal._hyper_1_1_chunk | tablespace1
_timescaledb_internal._hyper_1_2_chunk | tablespace2
(2 rows)
--indexes should inherit the tablespace of their chunk
SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
Table | Index | Columns | Unique | Primary | Exclusion | Tablespace
----------------------------------------+--------------------------------------------------------------------+--------------------+--------+---------+-----------+-------------
_timescaledb_internal._hyper_1_1_chunk | _timescaledb_internal._hyper_1_1_chunk_tspace_2dim_time_idx | {time,temp,device} | f | f | f | tablespace1
_timescaledb_internal._hyper_1_1_chunk | _timescaledb_internal._hyper_1_1_chunk_tspace_2dim_device_time_idx | {time,temp,device} | f | f | f | tablespace1
_timescaledb_internal._hyper_1_2_chunk | _timescaledb_internal._hyper_1_2_chunk_tspace_2dim_time_idx | {time,temp,device} | f | f | f | tablespace1
_timescaledb_internal._hyper_1_2_chunk | _timescaledb_internal._hyper_1_2_chunk_tspace_2dim_device_time_idx | {time,temp,device} | f | f | f | tablespace1
(4 rows)
--
SET ROLE :ROLE_DEFAULT_PERM_USER_2;
-- User doesn't have permission on tablespace1 --> error
CREATE TABLE tspace_1dim(time timestamp, temp float, device text) TABLESPACE tablespace1;
ERROR: permission denied for tablespace tablespace1
CREATE TABLE tspace_1dim(time timestamp, temp float, device text);
-- Grant permission to tablespace1
SET ROLE :ROLE_DEFAULT_PERM_USER;
GRANT CREATE ON TABLESPACE tablespace1 TO :ROLE_DEFAULT_PERM_USER_2;
SET ROLE :ROLE_DEFAULT_PERM_USER_2;
CREATE TABLE tspace_1dim(time timestamp, temp float, device text) TABLESPACE tablespace1;
CREATE TABLE tspace_1dim(time timestamp, temp float, device text);
ERROR: relation "tspace_1dim" already exists
SELECT create_hypertable('tspace_1dim', 'time');
NOTICE: Adding NOT NULL constraint to time column time (NULL time values not allowed)
create_hypertable
@ -103,6 +111,12 @@ NOTICE: Adding NOT NULL constraint to time column time (NULL time values not al
(1 row)
SELECT attach_tablespace('tablespace1', 'tspace_1dim');
attach_tablespace
-------------------
(1 row)
SELECT attach_tablespace('tablespace2', 'tspace_1dim');
attach_tablespace
-------------------
@ -120,17 +134,33 @@ SELECT * FROM _timescaledb_catalog.tablespace;
INSERT INTO tspace_1dim VALUES ('2017-01-20T09:00:01', 24.3, 'blue');
INSERT INTO tspace_1dim VALUES ('2017-03-20T09:00:01', 24.3, 'brown');
SELECT relname, spcname FROM pg_class c
INNER JOIN pg_tablespace t ON (c.reltablespace = t.oid)
INNER JOIN _timescaledb_catalog.chunk ch ON (ch.table_name = c.relname);
relname | spcname
------------------+-------------
_hyper_1_1_chunk | tablespace1
_hyper_1_2_chunk | tablespace2
_hyper_2_3_chunk | tablespace1
_hyper_2_4_chunk | tablespace2
SELECT * FROM test.show_subtablesp('tspace_%');
Parent | Child | Tablespace
-------------+----------------------------------------+-------------
tspace_2dim | _timescaledb_internal._hyper_1_1_chunk | tablespace1
tspace_2dim | _timescaledb_internal._hyper_1_2_chunk | tablespace2
tspace_1dim | _timescaledb_internal._hyper_2_3_chunk | tablespace1
tspace_1dim | _timescaledb_internal._hyper_2_4_chunk | tablespace2
(4 rows)
--indexes should inherit the tablespace of their chunk, unless the
--parent index has a tablespace set, in which case the chunks'
--corresponding indexes are pinned to the parent index's
--tablespace. The parent index can have a tablespace set in two cases:
--(1) if explicitly set in CREATE INDEX, or (2) if the main table was
--created with a tablespace, because then default indexes will be
--created in that tablespace too.
SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
Table | Index | Columns | Unique | Primary | Exclusion | Tablespace
----------------------------------------+--------------------------------------------------------------------+--------------------+--------+---------+-----------+-------------
_timescaledb_internal._hyper_1_1_chunk | _timescaledb_internal._hyper_1_1_chunk_tspace_2dim_time_idx | {time,temp,device} | f | f | f | tablespace1
_timescaledb_internal._hyper_1_1_chunk | _timescaledb_internal._hyper_1_1_chunk_tspace_2dim_device_time_idx | {time,temp,device} | f | f | f | tablespace1
_timescaledb_internal._hyper_1_2_chunk | _timescaledb_internal._hyper_1_2_chunk_tspace_2dim_time_idx | {time,temp,device} | f | f | f | tablespace1
_timescaledb_internal._hyper_1_2_chunk | _timescaledb_internal._hyper_1_2_chunk_tspace_2dim_device_time_idx | {time,temp,device} | f | f | f | tablespace1
_timescaledb_internal._hyper_2_3_chunk | _timescaledb_internal._hyper_2_3_chunk_tspace_1dim_time_idx | {time,temp,device} | f | f | f | tablespace2
_timescaledb_internal._hyper_2_4_chunk | _timescaledb_internal._hyper_2_4_chunk_tspace_1dim_time_idx | {time,temp,device} | f | f | f | tablespace1
(6 rows)
--detach tablespace1 from all tables. Due to lack of permissions,
--should only detach from 'tspace_1dim' (1 tablespace)
SELECT detach_tablespace('tablespace1');

View File

@ -45,12 +45,12 @@ SELECT * FROM _timescaledb_catalog.chunk;
(4 rows)
SELECT * FROM test.show_subtables('"two_Partitions"');
Child
----------------------------------------
_timescaledb_internal._hyper_1_1_chunk
_timescaledb_internal._hyper_1_2_chunk
_timescaledb_internal._hyper_1_3_chunk
_timescaledb_internal._hyper_1_4_chunk
Child | Tablespace
----------------------------------------+------------
_timescaledb_internal._hyper_1_1_chunk |
_timescaledb_internal._hyper_1_2_chunk |
_timescaledb_internal._hyper_1_3_chunk |
_timescaledb_internal._hyper_1_4_chunk |
(4 rows)
SELECT * FROM "two_Partitions";
@ -85,8 +85,8 @@ SELECT * FROM _timescaledb_catalog.chunk;
-- should be empty
SELECT * FROM test.show_subtables('"two_Partitions"');
Child
-------
Child | Tablespace
-------+------------
(0 rows)
SELECT * FROM "two_Partitions";
@ -140,8 +140,8 @@ WARNING: FIRING trigger when: BEFORE level: STATEMENT op: TRUNCATE cnt: <NULL>
WARNING: FIRING trigger when: AFTER level: STATEMENT op: TRUNCATE cnt: <NULL> trigger_name _test_truncate_after
-- should be empty
SELECT * FROM test.show_subtables('"two_Partitions"');
Child
-------
Child | Tablespace
-------+------------
(0 rows)
SELECT * FROM "two_Partitions";

View File

@ -57,22 +57,24 @@ SELECT * FROM show_tablespaces('tspace_2dim');
--insert into another chunk
INSERT INTO tspace_2dim VALUES ('2017-01-20T09:00:01', 24.3, 'brown');
SELECT relname, spcname FROM pg_class c
INNER JOIN pg_tablespace t ON (c.reltablespace = t.oid)
INNER JOIN _timescaledb_catalog.chunk ch ON (ch.table_name = c.relname);
SELECT * FROM test.show_subtables('tspace_2dim');
--indexes should inherit the tablespace of their chunk
SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
--
SET ROLE :ROLE_DEFAULT_PERM_USER_2;
-- User doesn't have permission on tablespace1 --> error
CREATE TABLE tspace_1dim(time timestamp, temp float, device text) TABLESPACE tablespace1;
CREATE TABLE tspace_1dim(time timestamp, temp float, device text);
-- Grant permission to tablespace1
SET ROLE :ROLE_DEFAULT_PERM_USER;
GRANT CREATE ON TABLESPACE tablespace1 TO :ROLE_DEFAULT_PERM_USER_2;
SET ROLE :ROLE_DEFAULT_PERM_USER_2;
CREATE TABLE tspace_1dim(time timestamp, temp float, device text) TABLESPACE tablespace1;
CREATE TABLE tspace_1dim(time timestamp, temp float, device text);
SELECT create_hypertable('tspace_1dim', 'time');
SELECT attach_tablespace('tablespace1', 'tspace_1dim');
SELECT attach_tablespace('tablespace2', 'tspace_1dim');
SELECT * FROM _timescaledb_catalog.tablespace;
@ -80,9 +82,15 @@ SELECT * FROM _timescaledb_catalog.tablespace;
INSERT INTO tspace_1dim VALUES ('2017-01-20T09:00:01', 24.3, 'blue');
INSERT INTO tspace_1dim VALUES ('2017-03-20T09:00:01', 24.3, 'brown');
SELECT relname, spcname FROM pg_class c
INNER JOIN pg_tablespace t ON (c.reltablespace = t.oid)
INNER JOIN _timescaledb_catalog.chunk ch ON (ch.table_name = c.relname);
SELECT * FROM test.show_subtablesp('tspace_%');
--indexes should inherit the tablespace of their chunk, unless the
--parent index has a tablespace set, in which case the chunks'
--corresponding indexes are pinned to the parent index's
--tablespace. The parent index can have a tablespace set in two cases:
--(1) if explicitly set in CREATE INDEX, or (2) if the main table was
--created with a tablespace, because then default indexes will be
--created in that tablespace too.
SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
--detach tablespace1 from all tables. Due to lack of permissions,
--should only detach from 'tspace_1dim' (1 tablespace)

View File

@ -198,19 +198,22 @@ END
$BODY$;
CREATE OR REPLACE FUNCTION test.show_subtables(rel regclass)
RETURNS TABLE("Child" regclass) LANGUAGE SQL STABLE AS
RETURNS TABLE("Child" regclass,
"Tablespace" name) LANGUAGE SQL STABLE AS
$BODY$
SELECT objid::regclass
FROM pg_depend d
SELECT objid::regclass, (SELECT t.spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace)
FROM pg_depend d, pg_class c
WHERE d.refobjid = rel
AND d.deptype = 'n'
AND d.classid = 'pg_class'::regclass
AND d.objid = c.oid
ORDER BY d.refobjid, d.objid;
$BODY$;
CREATE OR REPLACE FUNCTION test.show_subtablesp(pattern text)
RETURNS TABLE("Parent" regclass,
"Child" regclass) LANGUAGE PLPGSQL STABLE AS
"Child" regclass,
"Tablespace" name) LANGUAGE PLPGSQL STABLE AS
$BODY$
DECLARE
schema_name name = split_part(pattern, '.', 1);
@ -223,7 +226,8 @@ BEGIN
RETURN QUERY
SELECT refobjid::regclass,
objid::regclass
objid::regclass,
(SELECT t.spcname FROM pg_class cc, pg_tablespace t WHERE cc.oid = d.objid AND t.oid = cc.reltablespace)
FROM pg_class c, pg_depend d
WHERE format('%I.%I', c.relnamespace::regnamespace::name, c.relname) LIKE format('%I.%s', schema_name, table_name)
AND d.refobjid = c.oid