Skip to content

Commit 78296c2

Browse files
committed
Further cleanup for OR-of-AND WHERE-clauses. orindxpath can now handle
extracting from an AND subclause just those opclauses that are relevant for a particular index. For example, we can now consider using an index on x to process WHERE (x = 1 AND y = 2) OR (x = 2 AND y = 4) OR ...
1 parent dd14cd6 commit 78296c2

File tree

3 files changed

+102
-62
lines changed

3 files changed

+102
-62
lines changed

src/backend/optimizer/path/indxpath.c

Lines changed: 68 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.78 2000/01/26 05:56:34 momjian Exp $
12+
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.79 2000/02/05 18:26:09 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -51,15 +51,12 @@ typedef enum {
5151
} Prefix_Status;
5252

5353
static void match_index_orclauses(RelOptInfo *rel, IndexOptInfo *index,
54-
int indexkey, Oid opclass,
5554
List *restrictinfo_list);
5655
static List *match_index_orclause(RelOptInfo *rel, IndexOptInfo *index,
57-
int indexkey, Oid opclass,
5856
List *or_clauses,
5957
List *other_matching_indices);
6058
static bool match_or_subclause_to_indexkey(RelOptInfo *rel,
6159
IndexOptInfo *index,
62-
int indexkey, Oid opclass,
6360
Expr *clause);
6461
static List *group_clauses_by_indexkey(RelOptInfo *rel, IndexOptInfo *index,
6562
int *indexkeys, Oid *classes,
@@ -174,20 +171,11 @@ create_index_paths(Query *root,
174171
* so we can't build a path for an 'or' clause until all indexes have
175172
* been matched against it.)
176173
*
177-
* We currently only look to match the first key of each index against
178-
* 'or' subclauses. There are cases where a later key of a multi-key
179-
* index could be used (if other top-level clauses match earlier keys
180-
* of the index), but our poor brains are hurting already...
181-
*
182174
* We don't even think about special handling of 'or' clauses that
183175
* involve more than one relation (ie, are join clauses).
184176
* Can we do anything useful with those?
185177
*/
186-
match_index_orclauses(rel,
187-
index,
188-
index->indexkeys[0],
189-
index->classlist[0],
190-
restrictinfo_list);
178+
match_index_orclauses(rel, index, restrictinfo_list);
191179

192180
/*
193181
* 2. If the keys of this index match any of the available non-'or'
@@ -267,15 +255,11 @@ create_index_paths(Query *root,
267255
*
268256
* 'rel' is the node of the relation on which the index is defined.
269257
* 'index' is the index node.
270-
* 'indexkey' is the (single) key of the index that we will consider.
271-
* 'class' is the class of the operator corresponding to 'indexkey'.
272258
* 'restrictinfo_list' is the list of available restriction clauses.
273259
*/
274260
static void
275261
match_index_orclauses(RelOptInfo *rel,
276262
IndexOptInfo *index,
277-
int indexkey,
278-
Oid opclass,
279263
List *restrictinfo_list)
280264
{
281265
List *i;
@@ -292,7 +276,6 @@ match_index_orclauses(RelOptInfo *rel,
292276
*/
293277
restrictinfo->subclauseindices =
294278
match_index_orclause(rel, index,
295-
indexkey, opclass,
296279
restrictinfo->clause->args,
297280
restrictinfo->subclauseindices);
298281
}
@@ -305,9 +288,12 @@ match_index_orclauses(RelOptInfo *rel,
305288
*
306289
* A match means that:
307290
* (1) the operator within the subclause can be used with the
308-
* index's specified operator class, and
291+
* index's specified operator class, and
309292
* (2) one operand of the subclause matches the index key.
310293
*
294+
* If a subclause is an 'and' clause, then it matches if any of its
295+
* subclauses is an opclause that matches.
296+
*
311297
* 'or_clauses' is the list of subclauses within the 'or' clause
312298
* 'other_matching_indices' is the list of information on other indices
313299
* that have already been matched to subclauses within this
@@ -323,8 +309,6 @@ match_index_orclauses(RelOptInfo *rel,
323309
static List *
324310
match_index_orclause(RelOptInfo *rel,
325311
IndexOptInfo *index,
326-
int indexkey,
327-
Oid opclass,
328312
List *or_clauses,
329313
List *other_matching_indices)
330314
{
@@ -350,8 +334,7 @@ match_index_orclause(RelOptInfo *rel,
350334
{
351335
Expr *clause = lfirst(clist);
352336

353-
if (match_or_subclause_to_indexkey(rel, index, indexkey, opclass,
354-
clause))
337+
if (match_or_subclause_to_indexkey(rel, index, clause))
355338
{
356339
/* OK to add this index to sublist for this subclause */
357340
lfirst(matching_indices) = lcons(index,
@@ -368,33 +351,84 @@ match_index_orclause(RelOptInfo *rel,
368351
* See if a subclause of an OR clause matches an index.
369352
*
370353
* We accept the subclause if it is an operator clause that matches the
371-
* index, or if it is an AND clause all of whose members are operators
372-
* that match the index. (XXX Would accepting a single match be useful?)
354+
* index, or if it is an AND clause any of whose members is an opclause
355+
* that matches the index.
356+
*
357+
* We currently only look to match the first key of an index against
358+
* 'or' subclauses. There are cases where a later key of a multi-key
359+
* index could be used (if other top-level clauses match earlier keys
360+
* of the index), but our poor brains are hurting already...
373361
*/
374362
static bool
375363
match_or_subclause_to_indexkey(RelOptInfo *rel,
376364
IndexOptInfo *index,
377-
int indexkey,
378-
Oid opclass,
379365
Expr *clause)
380366
{
367+
int indexkey = index->indexkeys[0];
368+
Oid opclass = index->classlist[0];
369+
381370
if (and_clause((Node *) clause))
382371
{
383372
List *item;
384373

385374
foreach(item, clause->args)
386375
{
387-
if (! match_clause_to_indexkey(rel, index, indexkey, opclass,
388-
lfirst(item), false))
389-
return false;
376+
if (match_clause_to_indexkey(rel, index, indexkey, opclass,
377+
lfirst(item), false))
378+
return true;
390379
}
391-
return true;
380+
return false;
392381
}
393382
else
394383
return match_clause_to_indexkey(rel, index, indexkey, opclass,
395384
clause, false);
396385
}
397386

387+
/*
388+
* Given an OR subclause that has previously been determined to match
389+
* the specified index, extract a list of specific opclauses that can be
390+
* used as indexquals.
391+
*
392+
* In the simplest case this just means making a one-element list of the
393+
* given opclause. However, if the OR subclause is an AND, we have to
394+
* scan it to find the opclause(s) that match the index. (There should
395+
* be at least one, if match_or_subclause_to_indexkey succeeded, but there
396+
* could be more.) Also, we apply expand_indexqual_conditions() to convert
397+
* any special matching opclauses to indexable operators.
398+
*
399+
* The passed-in clause is not changed.
400+
*/
401+
List *
402+
extract_or_indexqual_conditions(RelOptInfo *rel,
403+
IndexOptInfo *index,
404+
Expr *orsubclause)
405+
{
406+
List *quals = NIL;
407+
int indexkey = index->indexkeys[0];
408+
Oid opclass = index->classlist[0];
409+
410+
if (and_clause((Node *) orsubclause))
411+
{
412+
List *item;
413+
414+
foreach(item, orsubclause->args)
415+
{
416+
if (match_clause_to_indexkey(rel, index, indexkey, opclass,
417+
lfirst(item), false))
418+
quals = lappend(quals, lfirst(item));
419+
}
420+
if (quals == NIL)
421+
elog(ERROR, "extract_or_indexqual_conditions: no matching clause");
422+
}
423+
else
424+
{
425+
/* we assume the caller passed a valid indexable qual */
426+
quals = lcons(orsubclause, NIL);
427+
}
428+
429+
return expand_indexqual_conditions(quals);
430+
}
431+
398432

399433
/****************************************************************************
400434
* ---- ROUTINES TO CHECK RESTRICTIONS ----
@@ -614,8 +648,8 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel,
614648
*
615649
* Returns true if the clause can be used with this index key.
616650
*
617-
* NOTE: returns false if clause is an OR or AND clause; to the extent
618-
* we cope with those at all, it is done by higher-level routines.
651+
* NOTE: returns false if clause is an OR or AND clause; it is the
652+
* responsibility of higher-level routines to cope with those.
619653
*/
620654
static bool
621655
match_clause_to_indexkey(RelOptInfo *rel,

src/backend/optimizer/path/orindxpath.c

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,12 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.35 2000/01/26 05:56:34 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.36 2000/02/05 18:26:09 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
15-
#include "postgres.h"
16-
17-
1815

16+
#include "postgres.h"
1917

2018
#include "nodes/nodeFuncs.h"
2119
#include "optimizer/clauses.h"
@@ -33,7 +31,8 @@ static void best_or_subclause_indices(Query *root, RelOptInfo *rel,
3331
List **indexids,
3432
Cost *cost);
3533
static void best_or_subclause_index(Query *root, RelOptInfo *rel,
36-
List *indexqual, List *indices,
34+
Expr *subclause, List *indices,
35+
List **retIndexQual,
3736
Oid *retIndexid,
3837
Cost *retCost);
3938

@@ -43,7 +42,7 @@ static void best_or_subclause_index(Query *root, RelOptInfo *rel,
4342
* Creates index paths for indices that match 'or' clauses.
4443
* create_index_paths() must already have been called.
4544
*
46-
* 'rel' is the relation entry for which the paths are to be defined on
45+
* 'rel' is the relation entry for which the paths are to be created
4746
* 'clauses' is the list of available restriction clause nodes
4847
*
4948
* Returns a list of index path nodes.
@@ -164,21 +163,16 @@ best_or_subclause_indices(Query *root,
164163
foreach(slist, subclauses)
165164
{
166165
Expr *subclause = lfirst(slist);
167-
List *indexqual;
166+
List *best_indexqual;
168167
Oid best_indexid;
169168
Cost best_cost;
170169

171-
/* Convert this 'or' subclause to an indexqual list */
172-
indexqual = make_ands_implicit(subclause);
173-
/* expand special operators to indexquals the executor can handle */
174-
indexqual = expand_indexqual_conditions(indexqual);
175-
176-
best_or_subclause_index(root, rel, indexqual, lfirst(indices),
177-
&best_indexid, &best_cost);
170+
best_or_subclause_index(root, rel, subclause, lfirst(indices),
171+
&best_indexqual, &best_indexid, &best_cost);
178172

179173
Assert(best_indexid != InvalidOid);
180174

181-
*indexquals = lappend(*indexquals, indexqual);
175+
*indexquals = lappend(*indexquals, best_indexqual);
182176
*indexids = lappendi(*indexids, best_indexid);
183177
*cost += best_cost;
184178

@@ -193,41 +187,49 @@ best_or_subclause_indices(Query *root,
193187
* the least expensive.
194188
*
195189
* 'rel' is the node of the relation on which the index is defined
196-
* 'indexqual' is the indexqual list derived from the subclause
190+
* 'subclause' is the OR subclause being considered
197191
* 'indices' is a list of IndexOptInfo nodes that match the subclause
192+
* '*retIndexQual' gets a list of the indexqual conditions for the best index
198193
* '*retIndexid' gets the OID of the best index
199194
* '*retCost' gets the cost of a scan with that index
200195
*/
201196
static void
202197
best_or_subclause_index(Query *root,
203198
RelOptInfo *rel,
204-
List *indexqual,
199+
Expr *subclause,
205200
List *indices,
201+
List **retIndexQual, /* return value */
206202
Oid *retIndexid, /* return value */
207203
Cost *retCost) /* return value */
208204
{
209-
bool first_run = true;
205+
bool first_time = true;
210206
List *ilist;
211207

212208
/* if we don't match anything, return zeros */
209+
*retIndexQual = NIL;
213210
*retIndexid = InvalidOid;
214211
*retCost = 0.0;
215212

216213
foreach(ilist, indices)
217214
{
218215
IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
216+
List *indexqual;
219217
Cost subcost;
220218

221219
Assert(IsA(index, IndexOptInfo));
222220

221+
/* Convert this 'or' subclause to an indexqual list */
222+
indexqual = extract_or_indexqual_conditions(rel, index, subclause);
223+
223224
subcost = cost_index(root, rel, index, indexqual,
224225
false);
225226

226-
if (first_run || subcost < *retCost)
227+
if (first_time || subcost < *retCost)
227228
{
229+
*retIndexQual = indexqual;
228230
*retIndexid = index->indexoid;
229231
*retCost = subcost;
230-
first_run = false;
232+
first_time = false;
231233
}
232234
}
233235
}

src/include/optimizer/paths.h

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
99
* Portions Copyright (c) 1994, Regents of the University of California
1010
*
11-
* $Id: paths.h,v 1.39 2000/01/26 05:58:20 momjian Exp $
11+
* $Id: paths.h,v 1.40 2000/02/05 18:26:07 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -38,8 +38,18 @@ extern List *create_index_paths(Query *root, RelOptInfo *rel, List *indices,
3838
List *joininfo_list);
3939
extern Oid indexable_operator(Expr *clause, Oid opclass, Oid relam,
4040
bool indexkey_on_left);
41+
extern List *extract_or_indexqual_conditions(RelOptInfo *rel,
42+
IndexOptInfo *index,
43+
Expr *orsubclause);
4144
extern List *expand_indexqual_conditions(List *indexquals);
4245

46+
/*
47+
* orindxpath.c
48+
* additional routines for indexable OR clauses
49+
*/
50+
extern List *create_or_index_paths(Query *root, RelOptInfo *rel,
51+
List *clauses);
52+
4353
/*
4454
* tidpath.h
4555
* routines to generate tid paths
@@ -52,12 +62,6 @@ extern List *create_tidscan_paths(Query *root, RelOptInfo *rel);
5262
*/
5363
extern void update_rels_pathlist_for_joins(Query *root, List *joinrels);
5464

55-
56-
/*
57-
* orindxpath.c
58-
*/
59-
extern List *create_or_index_paths(Query *root, RelOptInfo *rel, List *clauses);
60-
6165
/*
6266
* pathkeys.c
6367
* utilities for matching and building path keys
@@ -100,7 +104,7 @@ extern bool nonoverlap_sets(List *s1, List *s2);
100104
extern bool is_subset(List *s1, List *s2);
101105

102106
/*
103-
* prototypes for path/prune.c
107+
* prune.c
104108
*/
105109
extern void merge_rels_with_same_relids(List *rel_list);
106110
extern void rels_set_cheapest(Query *root, List *rel_list);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy