提高查询性能(仅限 C++)
在评估查询时,Vertica 可以利用有关值范围的可用信息。例如,如果数据已分区并且查询通过分区值限制输出,则 Vertica 可以忽略不可能包含满足查询的数据的分区。同样,对于标量函数,Vertica 可以不处理数据中函数返回的值不可能影响结果的行。
考虑一个表(表中包含数百万行客户订单数据)和一个标量函数(该函数计算为订单中的所有项目支付的总价格)。查询使用 WHERE 子句将结果限制为高于给定值的订单。对数据块调用标量函数;如果该块中没有行可以产生目标值,则跳过该块的处理可以提高查询性能。
用 C++ 编写的标量函数可以实施 getOutputRange
方法。在调用 processBlock
之前,Vertica 调用 getOutputRange
以在给定输入范围的情况下确定此块的最小和最大返回值。然后,它决定是否调用 processBlock
来执行计算。
Add2Ints 示例实施了此函数。最小输出值是两个输入的最小值之和,最大输出值是每个输入的最大值之和。此函数不考虑单个行。考虑以下输入:
a | b
------+------
21 | 92
500 | 19
111 | 11
两个输入的最小值是 21 和 11,因此函数将 32 报告为输出范围的下限。最大输入值为 500 和 92,因此它将 592 报告为输出范围的上限。任何输入行的返回值均大于 32,小于 592。
getOutputRange
的目的是快速消除输出肯定超出范围的调用。例如,如果查询包含 "WHERE Add2Ints(a,b) > 600",则可以跳过该数据块。仍然可能存在调用 getOutputRange
后 processBlock
没有返回结果的情况。如果查询包含 "WHERE Add2Ints(a,b) > 500",则 getOutputRange
不会消除此数据块。
Add2Ints 实施 getOutputRange
,如下所示:
/*
* This method computes the output range for this scalar function from
* the ranges of its inputs in a single invocation.
*
* The input ranges are retrieved via inRange
* The output range is returned via outRange
*/
virtual void getOutputRange(Vertica::ServerInterface &srvInterface,
Vertica::ValueRangeReader &inRange,
Vertica::ValueRangeWriter &outRange)
{
if (inRange.hasBounds(0) && inRange.hasBounds(1)) {
// Input ranges have bounds defined
if (inRange.isNull(0) || inRange.isNull(1)) {
// At least one range has only NULL values.
// Output range can only have NULL values.
outRange.setNull();
outRange.setHasBounds();
return;
} else {
// Compute output range
const vint& a1LoBound = inRange.getIntRefLo(0);
const vint& a2LoBound = inRange.getIntRefLo(1);
outRange.setIntLo(a1LoBound + a2LoBound);
const vint& a1UpBound = inRange.getIntRefUp(0);
const vint& a2UpBound = inRange.getIntRefUp(1);
outRange.setIntUp(a1UpBound + a2UpBound);
}
} else {
// Input ranges are unbounded. No output range can be defined
return;
}
if (!inRange.canHaveNulls(0) && !inRange.canHaveNulls(1)) {
// There cannot be NULL values in the output range
outRange.setCanHaveNulls(false);
}
// Let Vertica know that the output range is bounded
outRange.setHasBounds();
}
如果 getOutputRange
产生错误,Vertica 会发出警告并且不会为当前查询再次调用该方法。