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.189 2007/11/15 22:25:15 momjian Exp $
57
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.190 2007/12/08 21:05:11 tgl Exp $
58
58
*
59
59
*-------------------------------------------------------------------------
60
60
*/
@@ -1372,12 +1372,16 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
1372
1372
double outer_path_rows = PATH_ROWS (outer_path );
1373
1373
double inner_path_rows = PATH_ROWS (inner_path );
1374
1374
double outer_rows ,
1375
- inner_rows ;
1375
+ inner_rows ,
1376
+ outer_skip_rows ,
1377
+ inner_skip_rows ;
1376
1378
double mergejointuples ,
1377
1379
rescannedtuples ;
1378
1380
double rescanratio ;
1379
- Selectivity outerscansel ,
1380
- innerscansel ;
1381
+ Selectivity outerstartsel ,
1382
+ outerendsel ,
1383
+ innerstartsel ,
1384
+ innerendsel ;
1381
1385
Selectivity joininfactor ;
1382
1386
Path sort_path ; /* dummy for result of cost_sort */
1383
1387
@@ -1444,10 +1448,12 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
1444
1448
* A merge join will stop as soon as it exhausts either input stream
1445
1449
* (unless it's an outer join, in which case the outer side has to be
1446
1450
* scanned all the way anyway). Estimate fraction of the left and right
1447
- * inputs that will actually need to be scanned. We use only the first
1448
- * (most significant) merge clause for this purpose. Since
1449
- * mergejoinscansel() is a fairly expensive computation, we cache the
1450
- * results in the merge clause RestrictInfo.
1451
+ * inputs that will actually need to be scanned. Likewise, we can
1452
+ * estimate the number of rows that will be skipped before the first
1453
+ * join pair is found, which should be factored into startup cost.
1454
+ * We use only the first (most significant) merge clause for this purpose.
1455
+ * Since mergejoinscansel() is a fairly expensive computation, we cache
1456
+ * the results in the merge clause RestrictInfo.
1451
1457
*/
1452
1458
if (mergeclauses && path -> jpath .jointype != JOIN_FULL )
1453
1459
{
@@ -1478,37 +1484,61 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
1478
1484
outer_path -> parent -> relids ))
1479
1485
{
1480
1486
/* left side of clause is outer */
1481
- outerscansel = cache -> leftscansel ;
1482
- innerscansel = cache -> rightscansel ;
1487
+ outerstartsel = cache -> leftstartsel ;
1488
+ outerendsel = cache -> leftendsel ;
1489
+ innerstartsel = cache -> rightstartsel ;
1490
+ innerendsel = cache -> rightendsel ;
1483
1491
}
1484
1492
else
1485
1493
{
1486
1494
/* left side of clause is inner */
1487
- outerscansel = cache -> rightscansel ;
1488
- innerscansel = cache -> leftscansel ;
1495
+ outerstartsel = cache -> rightstartsel ;
1496
+ outerendsel = cache -> rightendsel ;
1497
+ innerstartsel = cache -> leftstartsel ;
1498
+ innerendsel = cache -> leftendsel ;
1489
1499
}
1490
1500
if (path -> jpath .jointype == JOIN_LEFT )
1491
- outerscansel = 1.0 ;
1501
+ {
1502
+ outerstartsel = 0.0 ;
1503
+ outerendsel = 1.0 ;
1504
+ }
1492
1505
else if (path -> jpath .jointype == JOIN_RIGHT )
1493
- innerscansel = 1.0 ;
1506
+ {
1507
+ innerstartsel = 0.0 ;
1508
+ innerendsel = 1.0 ;
1509
+ }
1494
1510
}
1495
1511
else
1496
1512
{
1497
1513
/* cope with clauseless or full mergejoin */
1498
- outerscansel = innerscansel = 1.0 ;
1514
+ outerstartsel = innerstartsel = 0.0 ;
1515
+ outerendsel = innerendsel = 1.0 ;
1499
1516
}
1500
1517
1501
- /* convert selectivity to row count; must scan at least one row */
1502
- outer_rows = clamp_row_est (outer_path_rows * outerscansel );
1503
- inner_rows = clamp_row_est (inner_path_rows * innerscansel );
1518
+ /*
1519
+ * Convert selectivities to row counts. We force outer_rows and
1520
+ * inner_rows to be at least 1, but the skip_rows estimates can be zero.
1521
+ */
1522
+ outer_skip_rows = rint (outer_path_rows * outerstartsel );
1523
+ inner_skip_rows = rint (inner_path_rows * innerstartsel );
1524
+ outer_rows = clamp_row_est (outer_path_rows * outerendsel );
1525
+ inner_rows = clamp_row_est (inner_path_rows * innerendsel );
1526
+
1527
+ Assert (outer_skip_rows <= outer_rows );
1528
+ Assert (inner_skip_rows <= inner_rows );
1504
1529
1505
1530
/*
1506
1531
* Readjust scan selectivities to account for above rounding. This is
1507
1532
* normally an insignificant effect, but when there are only a few rows in
1508
1533
* the inputs, failing to do this makes for a large percentage error.
1509
1534
*/
1510
- outerscansel = outer_rows / outer_path_rows ;
1511
- innerscansel = inner_rows / inner_path_rows ;
1535
+ outerstartsel = outer_skip_rows / outer_path_rows ;
1536
+ innerstartsel = inner_skip_rows / inner_path_rows ;
1537
+ outerendsel = outer_rows / outer_path_rows ;
1538
+ innerendsel = inner_rows / inner_path_rows ;
1539
+
1540
+ Assert (outerstartsel <= outerendsel );
1541
+ Assert (innerstartsel <= innerendsel );
1512
1542
1513
1543
/* cost of source data */
1514
1544
@@ -1522,14 +1552,18 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
1522
1552
outer_path -> parent -> width ,
1523
1553
-1.0 );
1524
1554
startup_cost += sort_path .startup_cost ;
1555
+ startup_cost += (sort_path .total_cost - sort_path .startup_cost )
1556
+ * outerstartsel ;
1525
1557
run_cost += (sort_path .total_cost - sort_path .startup_cost )
1526
- * outerscansel ;
1558
+ * ( outerendsel - outerstartsel ) ;
1527
1559
}
1528
1560
else
1529
1561
{
1530
1562
startup_cost += outer_path -> startup_cost ;
1563
+ startup_cost += (outer_path -> total_cost - outer_path -> startup_cost )
1564
+ * outerstartsel ;
1531
1565
run_cost += (outer_path -> total_cost - outer_path -> startup_cost )
1532
- * outerscansel ;
1566
+ * ( outerendsel - outerstartsel ) ;
1533
1567
}
1534
1568
1535
1569
if (innersortkeys ) /* do we need to sort inner? */
@@ -1542,14 +1576,18 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
1542
1576
inner_path -> parent -> width ,
1543
1577
-1.0 );
1544
1578
startup_cost += sort_path .startup_cost ;
1579
+ startup_cost += (sort_path .total_cost - sort_path .startup_cost )
1580
+ * innerstartsel * rescanratio ;
1545
1581
run_cost += (sort_path .total_cost - sort_path .startup_cost )
1546
- * innerscansel * rescanratio ;
1582
+ * ( innerendsel - innerstartsel ) * rescanratio ;
1547
1583
}
1548
1584
else
1549
1585
{
1550
1586
startup_cost += inner_path -> startup_cost ;
1587
+ startup_cost += (inner_path -> total_cost - inner_path -> startup_cost )
1588
+ * innerstartsel * rescanratio ;
1551
1589
run_cost += (inner_path -> total_cost - inner_path -> startup_cost )
1552
- * innerscansel * rescanratio ;
1590
+ * ( innerendsel - innerstartsel ) * rescanratio ;
1553
1591
}
1554
1592
1555
1593
/* CPU costs */
@@ -1571,8 +1609,11 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
1571
1609
* joininfactor.
1572
1610
*/
1573
1611
startup_cost += merge_qual_cost .startup ;
1612
+ startup_cost += merge_qual_cost .per_tuple *
1613
+ (outer_skip_rows + inner_skip_rows * rescanratio );
1574
1614
run_cost += merge_qual_cost .per_tuple *
1575
- (outer_rows + inner_rows * rescanratio );
1615
+ ((outer_rows - outer_skip_rows ) +
1616
+ (inner_rows - inner_skip_rows ) * rescanratio );
1576
1617
1577
1618
/*
1578
1619
* For each tuple that gets through the mergejoin proper, we charge
@@ -1597,8 +1638,10 @@ cached_scansel(PlannerInfo *root, RestrictInfo *rinfo, PathKey *pathkey)
1597
1638
{
1598
1639
MergeScanSelCache * cache ;
1599
1640
ListCell * lc ;
1600
- Selectivity leftscansel ,
1601
- rightscansel ;
1641
+ Selectivity leftstartsel ,
1642
+ leftendsel ,
1643
+ rightstartsel ,
1644
+ rightendsel ;
1602
1645
MemoryContext oldcontext ;
1603
1646
1604
1647
/* Do we have this result already? */
@@ -1617,8 +1660,10 @@ cached_scansel(PlannerInfo *root, RestrictInfo *rinfo, PathKey *pathkey)
1617
1660
pathkey -> pk_opfamily ,
1618
1661
pathkey -> pk_strategy ,
1619
1662
pathkey -> pk_nulls_first ,
1620
- & leftscansel ,
1621
- & rightscansel );
1663
+ & leftstartsel ,
1664
+ & leftendsel ,
1665
+ & rightstartsel ,
1666
+ & rightendsel );
1622
1667
1623
1668
/* Cache the result in suitably long-lived workspace */
1624
1669
oldcontext = MemoryContextSwitchTo (root -> planner_cxt );
@@ -1627,8 +1672,10 @@ cached_scansel(PlannerInfo *root, RestrictInfo *rinfo, PathKey *pathkey)
1627
1672
cache -> opfamily = pathkey -> pk_opfamily ;
1628
1673
cache -> strategy = pathkey -> pk_strategy ;
1629
1674
cache -> nulls_first = pathkey -> pk_nulls_first ;
1630
- cache -> leftscansel = leftscansel ;
1631
- cache -> rightscansel = rightscansel ;
1675
+ cache -> leftstartsel = leftstartsel ;
1676
+ cache -> leftendsel = leftendsel ;
1677
+ cache -> rightstartsel = rightstartsel ;
1678
+ cache -> rightendsel = rightendsel ;
1632
1679
1633
1680
rinfo -> scansel_cache = lappend (rinfo -> scansel_cache , cache );
1634
1681
0 commit comments