5959 * Portions Copyright (c) 1994, Regents of the University of California
6060 *
6161 * IDENTIFICATION
62- * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.214 2010/01/05 21:53:58 rhaas Exp $
62+ * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.215 2010/02/19 21:49:10 tgl Exp $
6363 *
6464 *-------------------------------------------------------------------------
6565 */
@@ -1189,7 +1189,9 @@ cost_sort(Path *path, PlannerInfo *root,
11891189
11901190 /*
11911191 * Also charge a small amount (arbitrarily set equal to operator cost) per
1192- * extracted tuple. Note it's correct to use tuples not output_tuples
1192+ * extracted tuple. We don't charge cpu_tuple_cost because a Sort node
1193+ * doesn't do qual-checking or projection, so it has less overhead than
1194+ * most plan nodes. Note it's correct to use tuples not output_tuples
11931195 * here --- the upper LIMIT will pro-rate the run cost so we'd be double
11941196 * counting the LIMIT otherwise.
11951197 */
@@ -1222,14 +1224,18 @@ cost_material(Path *path,
12221224 long work_mem_bytes = work_mem * 1024L ;
12231225
12241226 /*
1225- * Whether spilling or not, charge 2x cpu_tuple_cost per tuple to reflect
1226- * bookkeeping overhead. (This rate must be more than cpu_tuple_cost;
1227+ * Whether spilling or not, charge 2x cpu_operator_cost per tuple to
1228+ * reflect bookkeeping overhead. (This rate must be more than what
1229+ * cost_rescan charges for materialize, ie, cpu_operator_cost per tuple;
12271230 * if it is exactly the same then there will be a cost tie between
12281231 * nestloop with A outer, materialized B inner and nestloop with B outer,
12291232 * materialized A inner. The extra cost ensures we'll prefer
1230- * materializing the smaller rel.)
1233+ * materializing the smaller rel.) Note that this is normally a good deal
1234+ * less than cpu_tuple_cost; which is OK because a Material plan node
1235+ * doesn't do qual-checking or projection, so it's got less overhead than
1236+ * most plan nodes.
12311237 */
1232- run_cost += 2 * cpu_tuple_cost * tuples ;
1238+ run_cost += 2 * cpu_operator_cost * tuples ;
12331239
12341240 /*
12351241 * If we will spill to disk, charge at the rate of seq_page_cost per page.
@@ -1830,19 +1836,19 @@ cost_mergejoin(MergePath *path, PlannerInfo *root, SpecialJoinInfo *sjinfo)
18301836 bare_inner_cost = inner_run_cost * rescanratio ;
18311837 /*
18321838 * When we interpose a Material node the re-fetch cost is assumed to be
1833- * just cpu_tuple_cost per tuple, independently of the underlying plan's
1834- * cost; but we have to charge an extra cpu_tuple_cost per original fetch
1835- * as well. Note that we're assuming the materialize node will never
1836- * spill to disk, since it only has to remember tuples back to the last
1837- * mark. (If there are a huge number of duplicates, our other cost
1839+ * just cpu_operator_cost per tuple, independently of the underlying
1840+ * plan's cost; and we charge an extra cpu_operator_cost per original
1841+ * fetch as well. Note that we're assuming the materialize node will
1842+ * never spill to disk, since it only has to remember tuples back to the
1843+ * last mark. (If there are a huge number of duplicates, our other cost
18381844 * factors will make the path so expensive that it probably won't get
18391845 * chosen anyway.) So we don't use cost_rescan here.
18401846 *
18411847 * Note: keep this estimate in sync with create_mergejoin_plan's labeling
18421848 * of the generated Material node.
18431849 */
18441850 mat_inner_cost = inner_run_cost +
1845- cpu_tuple_cost * inner_path_rows * rescanratio ;
1851+ cpu_operator_cost * inner_path_rows * rescanratio ;
18461852
18471853 /* Prefer materializing if it looks cheaper */
18481854 if (mat_inner_cost < bare_inner_cost )
@@ -2354,10 +2360,8 @@ cost_rescan(PlannerInfo *root, Path *path,
23542360 * rescan_startup_cost = 0 ;
23552361 * rescan_total_cost = path -> total_cost - path -> startup_cost ;
23562362 break ;
2357- case T_Material :
23582363 case T_CteScan :
23592364 case T_WorkTableScan :
2360- case T_Sort :
23612365 {
23622366 /*
23632367 * These plan types materialize their final result in a
@@ -2381,6 +2385,33 @@ cost_rescan(PlannerInfo *root, Path *path,
23812385 * rescan_total_cost = run_cost ;
23822386 }
23832387 break ;
2388+ case T_Material :
2389+ case T_Sort :
2390+ {
2391+ /*
2392+ * These plan types not only materialize their results, but
2393+ * do not implement qual filtering or projection. So they
2394+ * are even cheaper to rescan than the ones above. We charge
2395+ * only cpu_operator_cost per tuple. (Note: keep that in
2396+ * sync with the run_cost charge in cost_sort, and also see
2397+ * comments in cost_material before you change it.)
2398+ */
2399+ Cost run_cost = cpu_operator_cost * path -> parent -> rows ;
2400+ double nbytes = relation_byte_size (path -> parent -> rows ,
2401+ path -> parent -> width );
2402+ long work_mem_bytes = work_mem * 1024L ;
2403+
2404+ if (nbytes > work_mem_bytes )
2405+ {
2406+ /* It will spill, so account for re-read cost */
2407+ double npages = ceil (nbytes / BLCKSZ );
2408+
2409+ run_cost += seq_page_cost * npages ;
2410+ }
2411+ * rescan_startup_cost = 0 ;
2412+ * rescan_total_cost = run_cost ;
2413+ }
2414+ break ;
23842415 default :
23852416 * rescan_startup_cost = path -> startup_cost ;
23862417 * rescan_total_cost = path -> total_cost ;
0 commit comments