mirror of
https://github.com/postgres/postgres.git
synced 2025-12-22 17:42:17 +03:00
Fix performance problems with pg_index lookups (see, for example,
discussion of 5/19/00). pg_index is now searched for indexes of a relation using an indexscan. Moreover, this is done once and cached in the relcache entry for the relation, in the form of a list of OIDs for the indexes. This list is used by the parser and executor to drive lookups in the pg_index syscache when they want to know the properties of the indexes. Net result: index information will be fully cached for repetitive operations such as inserts.
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.114 2000/06/15 03:32:07 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.115 2000/06/17 21:48:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "tcop/tcopprot.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/relcache.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
#ifdef MULTIBYTE
|
||||
@@ -1081,78 +1082,43 @@ IsTypeByVal(Oid type)
|
||||
* Space for the array itself is palloc'ed.
|
||||
*/
|
||||
|
||||
typedef struct rel_list
|
||||
{
|
||||
Oid index_rel_oid;
|
||||
struct rel_list *next;
|
||||
} RelationList;
|
||||
|
||||
static void
|
||||
GetIndexRelations(Oid main_relation_oid,
|
||||
int *n_indices,
|
||||
Relation **index_rels)
|
||||
{
|
||||
RelationList *head,
|
||||
*scan;
|
||||
Relation pg_index_rel;
|
||||
HeapScanDesc scandesc;
|
||||
Oid index_relation_oid;
|
||||
HeapTuple tuple;
|
||||
TupleDesc tupDesc;
|
||||
Relation relation;
|
||||
List *indexoidlist,
|
||||
*indexoidscan;
|
||||
int i;
|
||||
bool isnull;
|
||||
|
||||
pg_index_rel = heap_openr(IndexRelationName, AccessShareLock);
|
||||
scandesc = heap_beginscan(pg_index_rel, 0, SnapshotNow, 0, NULL);
|
||||
tupDesc = RelationGetDescr(pg_index_rel);
|
||||
relation = heap_open(main_relation_oid, AccessShareLock);
|
||||
indexoidlist = RelationGetIndexList(relation);
|
||||
|
||||
*n_indices = 0;
|
||||
*n_indices = length(indexoidlist);
|
||||
|
||||
head = (RelationList *) palloc(sizeof(RelationList));
|
||||
scan = head;
|
||||
head->next = NULL;
|
||||
if (*n_indices > 0)
|
||||
*index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
|
||||
else
|
||||
*index_rels = NULL;
|
||||
|
||||
while (HeapTupleIsValid(tuple = heap_getnext(scandesc, 0)))
|
||||
i = 0;
|
||||
foreach(indexoidscan, indexoidlist)
|
||||
{
|
||||
Oid indexoid = lfirsti(indexoidscan);
|
||||
Relation index = index_open(indexoid);
|
||||
|
||||
index_relation_oid = (Oid) DatumGetInt32(heap_getattr(tuple, 2,
|
||||
tupDesc, &isnull));
|
||||
if (index_relation_oid == main_relation_oid)
|
||||
{
|
||||
scan->index_rel_oid = (Oid) DatumGetInt32(heap_getattr(tuple,
|
||||
Anum_pg_index_indexrelid,
|
||||
tupDesc, &isnull));
|
||||
(*n_indices)++;
|
||||
scan->next = (RelationList *) palloc(sizeof(RelationList));
|
||||
scan = scan->next;
|
||||
}
|
||||
}
|
||||
|
||||
heap_endscan(scandesc);
|
||||
heap_close(pg_index_rel, AccessShareLock);
|
||||
|
||||
/* We cannot trust to relhasindex of the main_relation now, so... */
|
||||
if (*n_indices == 0)
|
||||
return;
|
||||
|
||||
*index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
|
||||
|
||||
for (i = 0, scan = head; i < *n_indices; i++, scan = scan->next)
|
||||
{
|
||||
(*index_rels)[i] = index_open(scan->index_rel_oid);
|
||||
/* see comments in ExecOpenIndices() in execUtils.c */
|
||||
if ((*index_rels)[i] != NULL &&
|
||||
((*index_rels)[i])->rd_rel->relam != BTREE_AM_OID &&
|
||||
((*index_rels)[i])->rd_rel->relam != HASH_AM_OID)
|
||||
LockRelation((*index_rels)[i], AccessExclusiveLock);
|
||||
if (index != NULL &&
|
||||
index->rd_rel->relam != BTREE_AM_OID &&
|
||||
index->rd_rel->relam != HASH_AM_OID)
|
||||
LockRelation(index, AccessExclusiveLock);
|
||||
(*index_rels)[i] = index;
|
||||
i++;
|
||||
}
|
||||
|
||||
for (i = 0, scan = head; i < *n_indices + 1; i++)
|
||||
{
|
||||
scan = head->next;
|
||||
pfree(head);
|
||||
head = scan;
|
||||
}
|
||||
freeList(indexoidlist);
|
||||
heap_close(relation, AccessShareLock);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.29 2000/06/15 03:32:07 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.30 2000/06/17 21:48:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -221,6 +221,13 @@ DefineIndex(char *heapRelationName,
|
||||
lossy, unique, primary);
|
||||
}
|
||||
|
||||
/*
|
||||
* We update the relation's pg_class tuple even if it already has
|
||||
* relhasindex = true. This is needed to cause a shared-cache-inval
|
||||
* message to be sent for the pg_class tuple, which will cause other
|
||||
* backends to flush their relcache entries and in particular their
|
||||
* cached lists of the indexes for this relation.
|
||||
*/
|
||||
setRelhasindexInplace(relationId, true, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.159 2000/05/29 17:40:43 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.160 2000/06/17 21:48:43 tgl Exp $
|
||||
*
|
||||
|
||||
*-------------------------------------------------------------------------
|
||||
@@ -72,7 +72,7 @@ static void update_relstats(Oid relid, int num_pages, int num_tuples, bool hasin
|
||||
static VacPage tid_reaped(ItemPointer itemptr, VacPageList vacpagelist);
|
||||
static void reap_page(VacPageList vacpagelist, VacPage vacpage);
|
||||
static void vpage_insert(VacPageList vacpagelist, VacPage vpnew);
|
||||
static void get_indices(Oid relid, int *nindices, Relation **Irel);
|
||||
static void get_indices(Relation relation, int *nindices, Relation **Irel);
|
||||
static void close_indices(int nindices, Relation *Irel);
|
||||
static void get_index_desc(Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc);
|
||||
static void *vac_find_eq(void *bot, int nelem, int size, void *elm,
|
||||
@@ -416,7 +416,7 @@ vacuum_rel(Oid relid, bool analyze)
|
||||
/* Now open indices */
|
||||
nindices = 0;
|
||||
Irel = (Relation *) NULL;
|
||||
get_indices(vacrelstats->relid, &nindices, &Irel);
|
||||
get_indices(onerel, &nindices, &Irel);
|
||||
if (!Irel)
|
||||
reindex = false;
|
||||
else if (!RelationGetForm(onerel)->relhasindex)
|
||||
@@ -2331,80 +2331,33 @@ CommonSpecialPortalIsOpen(void)
|
||||
return CommonSpecialPortalInUse;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
get_indices(Oid relid, int *nindices, Relation **Irel)
|
||||
get_indices(Relation relation, int *nindices, Relation **Irel)
|
||||
{
|
||||
Relation pgindex;
|
||||
Relation irel;
|
||||
TupleDesc tupdesc;
|
||||
HeapTuple tuple;
|
||||
HeapScanDesc scan;
|
||||
Datum d;
|
||||
int i,
|
||||
k;
|
||||
bool n;
|
||||
ScanKeyData key;
|
||||
Oid *ioid;
|
||||
List *indexoidlist,
|
||||
*indexoidscan;
|
||||
int i;
|
||||
|
||||
*nindices = i = 0;
|
||||
indexoidlist = RelationGetIndexList(relation);
|
||||
|
||||
ioid = (Oid *) palloc(10 * sizeof(Oid));
|
||||
*nindices = length(indexoidlist);
|
||||
|
||||
/* prepare a heap scan on the pg_index relation */
|
||||
pgindex = heap_openr(IndexRelationName, AccessShareLock);
|
||||
tupdesc = RelationGetDescr(pgindex);
|
||||
if (*nindices > 0)
|
||||
*Irel = (Relation *) palloc(*nindices * sizeof(Relation));
|
||||
else
|
||||
*Irel = NULL;
|
||||
|
||||
ScanKeyEntryInitialize(&key, 0x0, Anum_pg_index_indrelid,
|
||||
F_OIDEQ,
|
||||
ObjectIdGetDatum(relid));
|
||||
|
||||
scan = heap_beginscan(pgindex, false, SnapshotNow, 1, &key);
|
||||
|
||||
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
||||
i = 0;
|
||||
foreach(indexoidscan, indexoidlist)
|
||||
{
|
||||
d = heap_getattr(tuple, Anum_pg_index_indexrelid,
|
||||
tupdesc, &n);
|
||||
Oid indexoid = lfirsti(indexoidscan);
|
||||
|
||||
(*Irel)[i] = index_open(indexoid);
|
||||
i++;
|
||||
if (i % 10 == 0)
|
||||
ioid = (Oid *) repalloc(ioid, (i + 10) * sizeof(Oid));
|
||||
ioid[i - 1] = DatumGetObjectId(d);
|
||||
}
|
||||
|
||||
heap_endscan(scan);
|
||||
heap_close(pgindex, AccessShareLock);
|
||||
|
||||
if (i == 0)
|
||||
{ /* No one index found */
|
||||
pfree(ioid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Irel != (Relation **) NULL)
|
||||
*Irel = (Relation *) palloc(i * sizeof(Relation));
|
||||
|
||||
for (k = 0; i > 0;)
|
||||
{
|
||||
irel = index_open(ioid[--i]);
|
||||
if (irel != (Relation) NULL)
|
||||
{
|
||||
if (Irel != (Relation **) NULL)
|
||||
(*Irel)[k] = irel;
|
||||
else
|
||||
index_close(irel);
|
||||
k++;
|
||||
}
|
||||
else
|
||||
elog(NOTICE, "CAN'T OPEN INDEX %u - SKIP IT", ioid[i]);
|
||||
}
|
||||
*nindices = k;
|
||||
pfree(ioid);
|
||||
|
||||
if (Irel != (Relation **) NULL && *nindices == 0)
|
||||
{
|
||||
pfree(*Irel);
|
||||
*Irel = (Relation *) NULL;
|
||||
}
|
||||
|
||||
freeList(indexoidlist);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user