* cdbpath_cost_motion * Fills in the cost estimate fields in a MotionPath node. */
| 81 | * Fills in the cost estimate fields in a MotionPath node. |
| 82 | */ |
| 83 | void |
| 84 | cdbpath_cost_motion(PlannerInfo *root, CdbMotionPath *motionpath) |
| 85 | { |
| 86 | Path *subpath = motionpath->subpath; |
| 87 | Cost cost_per_row; |
| 88 | Cost motioncost; |
| 89 | double recvrows; |
| 90 | double sendrows; |
| 91 | double send_segments = 1; |
| 92 | double recv_segments = 1; |
| 93 | double total_rows; |
| 94 | |
| 95 | CdbPathLocus sublocus = subpath->locus; |
| 96 | CdbPathLocus motionlocus = motionpath->path.locus; |
| 97 | |
| 98 | int mot_parallel = motionlocus.parallel_workers; |
| 99 | int sub_parallel = sublocus.parallel_workers; |
| 100 | |
| 101 | if (CdbPathLocus_IsPartitioned(motionlocus)) |
| 102 | { |
| 103 | recv_segments = CdbPathLocus_NumSegments(motionlocus); |
| 104 | if (mot_parallel > 0) |
| 105 | recv_segments *= mot_parallel; |
| 106 | } |
| 107 | else if (mot_parallel > 0 && CdbPathLocus_IsReplicatedWorkers(motionlocus)) |
| 108 | recv_segments *= mot_parallel; |
| 109 | |
| 110 | if (CdbPathLocus_IsPartitioned(sublocus)) |
| 111 | { |
| 112 | send_segments = CdbPathLocus_NumSegments(sublocus); |
| 113 | if (sub_parallel > 0) |
| 114 | send_segments *= sub_parallel; |
| 115 | } |
| 116 | else if (sub_parallel > 0 && CdbPathLocus_IsReplicatedWorkers(sublocus)) |
| 117 | send_segments *= sub_parallel; |
| 118 | |
| 119 | /* |
| 120 | * Estimate the total number of rows being sent. |
| 121 | * The base estimate is computed by multiplying the subpath's rows with |
| 122 | * the number of sending segments. But in some cases, that leads to too |
| 123 | * large estimates, if the subpath's estimate was "clamped" to 1 row. The |
| 124 | * typical example is a single-row select like "SELECT * FROM table WHERE |
| 125 | * key = 123. The Scan on the table returns only one row, on one segment, |
| 126 | * and the estimate on the Scan node is 1 row. If you have e.g. 3 |
| 127 | * segments, and we just multiplied the subpath's row estimate by 3, we |
| 128 | * would estimate that the Gather returns 3 rows, even though there is |
| 129 | * only one matching row in the table. Using the 'rows' estimate on the |
| 130 | * RelOptInfo is more accurate in such cases. To correct that, if the |
| 131 | * subpath's estimate is 1 row, but the underlying relation's estimate is |
| 132 | * smaller, use the underlying relation's estimate. |
| 133 | * |
| 134 | * We don't always use the relation's estimate, because there might be |
| 135 | * nodes like ProjectSet or Limit in the subpath, in which case the |
| 136 | * subpath's estimate is more accurate. Also, the relation might not have |
| 137 | * a valid 'rows' estimate; upper rels, for example, do not. So check for |
| 138 | * that too. |
| 139 | */ |
| 140 | total_rows = subpath->rows * send_segments; |
no test coverage detected