提交 62dffc6f authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Optimize window aggregates with ORDER BY + UNBOUNDED PRECEDING + no exclusions

上级 75ad6204
...@@ -16,6 +16,9 @@ import org.h2.engine.Session; ...@@ -16,6 +16,9 @@ import org.h2.engine.Session;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.expression.analysis.DataAnalysisOperation; import org.h2.expression.analysis.DataAnalysisOperation;
import org.h2.expression.analysis.WindowFrame; import org.h2.expression.analysis.WindowFrame;
import org.h2.expression.analysis.WindowFrameBound;
import org.h2.expression.analysis.WindowFrameBoundType;
import org.h2.expression.analysis.WindowFrameExclusion;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -84,12 +87,18 @@ public abstract class AbstractAggregate extends DataAnalysisOperation { ...@@ -84,12 +87,18 @@ public abstract class AbstractAggregate extends DataAnalysisOperation {
int rowIdColumn) { int rowIdColumn) {
WindowFrame frame = over.getWindowFrame(); WindowFrame frame = over.getWindowFrame();
if (frame == null) { if (frame == null) {
if (over.getOrderBy() == null) { assert over.getOrderBy() != null;
aggregateFastPartition(session, result, ordered, rowIdColumn);
return;
}
if (frame.getStarting().getType() == WindowFrameBoundType.UNBOUNDED_PRECEDING
&& frame.getExclusion() == WindowFrameExclusion.EXCLUDE_NO_OTHERS) {
WindowFrameBound following = frame.getFollowing();
if (following != null && following.getType() == WindowFrameBoundType.UNBOUNDED_FOLLOWING) {
aggregateWholePartition(session, result, ordered, rowIdColumn); aggregateWholePartition(session, result, ordered, rowIdColumn);
return; } else {
aggregateFastPartition(session, result, ordered, rowIdColumn);
} }
} else if (frame.isFullPartition()) {
aggregateWholePartition(session, result, ordered, rowIdColumn);
return; return;
} }
// All other types of frames (slow) // All other types of frames (slow)
...@@ -104,6 +113,24 @@ public abstract class AbstractAggregate extends DataAnalysisOperation { ...@@ -104,6 +113,24 @@ public abstract class AbstractAggregate extends DataAnalysisOperation {
} }
} }
private void aggregateFastPartition(Session session, HashMap<Integer, Value> result, ArrayList<Value[]> ordered,
int rowIdColumn) {
Object aggregateData = createAggregateData();
int size = ordered.size();
int lastIncludedRow = -1;
for (int i = 0; i < size; i++) {
int newLast = WindowFrame.getEndIndex(over, session, ordered, getOverOrderBySort(), i);
assert newLast >= lastIncludedRow;
if (newLast > lastIncludedRow) {
for (int j = lastIncludedRow + 1; j <= newLast; j++) {
updateFromExpressions(session, aggregateData, ordered.get(j));
}
lastIncludedRow = newLast;
}
result.put(ordered.get(i)[rowIdColumn].getInt(), getAggregatedValue(session, aggregateData));
}
}
private void aggregateWholePartition(Session session, HashMap<Integer, Value> result, ArrayList<Value[]> ordered, private void aggregateWholePartition(Session session, HashMap<Integer, Value> result, ArrayList<Value[]> ordered,
int rowIdColumn) { int rowIdColumn) {
// Aggregate values from the whole partition // Aggregate values from the whole partition
......
...@@ -219,6 +219,35 @@ public final class WindowFrame { ...@@ -219,6 +219,35 @@ public final class WindowFrame {
reverse); reverse);
} }
/**
* Returns end index for the specified frame, or default end index if frame
* is null.
*
* @param over
* window
* @param session
* the session
* @param orderedRows
* ordered rows
* @param sortOrder
* sort order
* @param currentRow
* index of the current row
* @return end index
* @throws UnsupportedOperationException
* if over is not null and its exclusion clause is not EXCLUDE
* NO OTHERS
*/
public static int getEndIndex(Window over, Session session, ArrayList<Value[]> orderedRows, SortOrder sortOrder,
int currentRow) {
WindowFrame frame = over.getWindowFrame();
if (frame != null) {
return frame.getEndIndex(session, orderedRows, sortOrder, currentRow);
}
int endIndex = orderedRows.size() - 1;
return over.getOrderBy() == null ? endIndex : toGroupEnd(orderedRows, sortOrder, currentRow, endIndex);
}
private static Iterator<Value[]> plainIterator(ArrayList<Value[]> orderedRows, int startIndex, int endIndex, private static Iterator<Value[]> plainIterator(ArrayList<Value[]> orderedRows, int startIndex, int endIndex,
boolean reverse) { boolean reverse) {
if (endIndex < startIndex) { if (endIndex < startIndex) {
...@@ -308,6 +337,42 @@ public final class WindowFrame { ...@@ -308,6 +337,42 @@ public final class WindowFrame {
this.exclusion = exclusion; this.exclusion = exclusion;
} }
/**
* Returns the units.
*
* @return the units
*/
public WindowFrameUnits getUnits() {
return units;
}
/**
* Returns the starting clause.
*
* @return the starting clause
*/
public WindowFrameBound getStarting() {
return starting;
}
/**
* Returns the following clause.
*
* @return the following clause, or null
*/
public WindowFrameBound getFollowing() {
return following;
}
/**
* Returns the exclusion clause.
*
* @return the exclusion clause
*/
public WindowFrameExclusion getExclusion() {
return exclusion;
}
/** /**
* Checks validity of this frame. * Checks validity of this frame.
* *
...@@ -320,18 +385,6 @@ public final class WindowFrame { ...@@ -320,18 +385,6 @@ public final class WindowFrame {
&& s.compareTo(f) <= 0; && s.compareTo(f) <= 0;
} }
/**
* Returns whether window frame specification contains all rows in
* partition.
*
* @return whether window frame specification contains all rows in partition
*/
public boolean isFullPartition() {
return starting.getType() == WindowFrameBoundType.UNBOUNDED_PRECEDING && following != null
&& following.getType() == WindowFrameBoundType.UNBOUNDED_FOLLOWING
&& exclusion == WindowFrameExclusion.EXCLUDE_NO_OTHERS;
}
/** /**
* Returns iterator. * Returns iterator.
* *
...@@ -345,7 +398,6 @@ public final class WindowFrame { ...@@ -345,7 +398,6 @@ public final class WindowFrame {
* index of the current row * index of the current row
* @param reverse * @param reverse
* whether iterator should iterate in reverse order * whether iterator should iterate in reverse order
*
* @return iterator * @return iterator
*/ */
public Iterator<Value[]> iterator(Session session, ArrayList<Value[]> orderedRows, SortOrder sortOrder, public Iterator<Value[]> iterator(Session session, ArrayList<Value[]> orderedRows, SortOrder sortOrder,
...@@ -372,6 +424,35 @@ public final class WindowFrame { ...@@ -372,6 +424,35 @@ public final class WindowFrame {
: plainIterator(orderedRows, startIndex, endIndex, reverse); : plainIterator(orderedRows, startIndex, endIndex, reverse);
} }
/**
* Returns end index of this frame,
*
* @param session
* the session
* @param orderedRows
* ordered rows
* @param sortOrder
* sort order
* @param currentRow
* index of the current row
* @return end index
* @throws UnsupportedOperationException
* if exclusion clause is not EXCLUDE NO OTHERS
*/
private int getEndIndex(Session session, ArrayList<Value[]> orderedRows, SortOrder sortOrder, int currentRow) {
if (exclusion != WindowFrameExclusion.EXCLUDE_NO_OTHERS) {
throw new UnsupportedOperationException();
}
int endIndex = following != null ? getIndex(session, orderedRows, sortOrder, currentRow, following, true)
: units == WindowFrameUnits.ROWS ? currentRow
: toGroupEnd(orderedRows, sortOrder, currentRow, orderedRows.size() - 1);
int size = orderedRows.size();
if (endIndex >= size) {
endIndex = size - 1;
}
return endIndex;
}
private int getIndex(Session session, ArrayList<Value[]> orderedRows, SortOrder sortOrder, int currentRow, private int getIndex(Session session, ArrayList<Value[]> orderedRows, SortOrder sortOrder, int currentRow,
WindowFrameBound bound, boolean forFollowing) { WindowFrameBound bound, boolean forFollowing) {
int size = orderedRows.size(); int size = orderedRows.size();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论