54
54
* Portions Copyright (c) 1994, Regents of the University of California
55
55
*
56
56
* IDENTIFICATION
57
- * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.176 2007/01/22 01:35:20 tgl Exp $
57
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.177 2007/01/22 20:00:39 tgl Exp $
58
58
*
59
59
*-------------------------------------------------------------------------
60
60
*/
@@ -108,6 +108,9 @@ bool enable_mergejoin = true;
108
108
bool enable_hashjoin = true;
109
109
110
110
111
+ static MergeScanSelCache * cached_scansel (PlannerInfo * root ,
112
+ RestrictInfo * rinfo ,
113
+ PathKey * pathkey );
111
114
static bool cost_qual_eval_walker (Node * node , QualCost * total );
112
115
static Selectivity approx_selectivity (PlannerInfo * root , List * quals ,
113
116
JoinType jointype );
@@ -1349,9 +1352,9 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
1349
1352
* (unless it's an outer join, in which case the outer side has to be
1350
1353
* scanned all the way anyway). Estimate fraction of the left and right
1351
1354
* inputs that will actually need to be scanned. We use only the first
1352
- * (most significant) merge clause for this purpose.
1353
- *
1354
- * XXX mergejoinscansel is a bit expensive, can we cache its results?
1355
+ * (most significant) merge clause for this purpose. Since
1356
+ * mergejoinscansel() is a fairly expensive computation, we cache the
1357
+ * results in the merge clause RestrictInfo.
1355
1358
*/
1356
1359
if (mergeclauses && path -> jpath .jointype != JOIN_FULL )
1357
1360
{
@@ -1360,8 +1363,7 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
1360
1363
List * ipathkeys ;
1361
1364
PathKey * opathkey ;
1362
1365
PathKey * ipathkey ;
1363
- Selectivity leftscansel ,
1364
- rightscansel ;
1366
+ MergeScanSelCache * cache ;
1365
1367
1366
1368
/* Get the input pathkeys to determine the sort-order details */
1367
1369
opathkeys = outersortkeys ? outersortkeys : outer_path -> pathkeys ;
@@ -1376,22 +1378,21 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
1376
1378
opathkey -> pk_nulls_first != ipathkey -> pk_nulls_first )
1377
1379
elog (ERROR , "left and right pathkeys do not match in mergejoin" );
1378
1380
1379
- mergejoinscansel (root , (Node * ) firstclause -> clause ,
1380
- opathkey -> pk_opfamily , opathkey -> pk_strategy ,
1381
- & leftscansel , & rightscansel );
1381
+ /* Get the selectivity with caching */
1382
+ cache = cached_scansel (root , firstclause , opathkey );
1382
1383
1383
1384
if (bms_is_subset (firstclause -> left_relids ,
1384
1385
outer_path -> parent -> relids ))
1385
1386
{
1386
1387
/* left side of clause is outer */
1387
- outerscansel = leftscansel ;
1388
- innerscansel = rightscansel ;
1388
+ outerscansel = cache -> leftscansel ;
1389
+ innerscansel = cache -> rightscansel ;
1389
1390
}
1390
1391
else
1391
1392
{
1392
1393
/* left side of clause is inner */
1393
- outerscansel = rightscansel ;
1394
- innerscansel = leftscansel ;
1394
+ outerscansel = cache -> rightscansel ;
1395
+ innerscansel = cache -> leftscansel ;
1395
1396
}
1396
1397
if (path -> jpath .jointype == JOIN_LEFT )
1397
1398
outerscansel = 1.0 ;
@@ -1493,6 +1494,54 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
1493
1494
path -> jpath .path .total_cost = startup_cost + run_cost ;
1494
1495
}
1495
1496
1497
+ /*
1498
+ * run mergejoinscansel() with caching
1499
+ */
1500
+ static MergeScanSelCache *
1501
+ cached_scansel (PlannerInfo * root , RestrictInfo * rinfo , PathKey * pathkey )
1502
+ {
1503
+ MergeScanSelCache * cache ;
1504
+ ListCell * lc ;
1505
+ Selectivity leftscansel ,
1506
+ rightscansel ;
1507
+ MemoryContext oldcontext ;
1508
+
1509
+ /* Do we have this result already? */
1510
+ foreach (lc , rinfo -> scansel_cache )
1511
+ {
1512
+ cache = (MergeScanSelCache * ) lfirst (lc );
1513
+ if (cache -> opfamily == pathkey -> pk_opfamily &&
1514
+ cache -> strategy == pathkey -> pk_strategy &&
1515
+ cache -> nulls_first == pathkey -> pk_nulls_first )
1516
+ return cache ;
1517
+ }
1518
+
1519
+ /* Nope, do the computation */
1520
+ mergejoinscansel (root ,
1521
+ (Node * ) rinfo -> clause ,
1522
+ pathkey -> pk_opfamily ,
1523
+ pathkey -> pk_strategy ,
1524
+ pathkey -> pk_nulls_first ,
1525
+ & leftscansel ,
1526
+ & rightscansel );
1527
+
1528
+ /* Cache the result in suitably long-lived workspace */
1529
+ oldcontext = MemoryContextSwitchTo (root -> planner_cxt );
1530
+
1531
+ cache = (MergeScanSelCache * ) palloc (sizeof (MergeScanSelCache ));
1532
+ cache -> opfamily = pathkey -> pk_opfamily ;
1533
+ cache -> strategy = pathkey -> pk_strategy ;
1534
+ cache -> nulls_first = pathkey -> pk_nulls_first ;
1535
+ cache -> leftscansel = leftscansel ;
1536
+ cache -> rightscansel = rightscansel ;
1537
+
1538
+ rinfo -> scansel_cache = lappend (rinfo -> scansel_cache , cache );
1539
+
1540
+ MemoryContextSwitchTo (oldcontext );
1541
+
1542
+ return cache ;
1543
+ }
1544
+
1496
1545
/*
1497
1546
* cost_hashjoin
1498
1547
* Determines and returns the cost of joining two relations using the
0 commit comments