Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reverse and incremental index sorting optimizations #4041

Merged
merged 2 commits into from Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions h2/src/docsrc/html/changelog.html
Expand Up @@ -21,6 +21,8 @@ <h1>Change Log</h1>

<h2>Next Version (unreleased)</h2>
<ul>
<li>Issue #701: An available index is never used for ordering, when the requested order is DESC
</li>
<li>Issue #4036: NULLS NOT DISTINCT constraint changed after column dropped
</li>
<li>Issue #4033: Wrong array produced when using ARRAY_AGG() on UNNEST(ARRAY[CAST(? AS INT)]) expression
Expand Down
11 changes: 11 additions & 0 deletions h2/src/docsrc/html/performance.html
Expand Up @@ -732,6 +732,17 @@ <h3>Special Optimizations</h3>
</p><p>
For queries of the form <code>SELECT * FROM TEST ORDER BY ID</code>, the query plan includes the line
<code>/* index sorted */</code> to indicate there is no separate sorting required.
<code>/* index sorted: 2 of 3 columns */</code> indicates that only some columns are sorted with an index.
An additional sorting is still required, but queries with the FETCH (TOP, LIMIT) clause
may still stop their execution earlier.
An index on <code>(A ASC, B ASC)</code> columns can be used for <code>ORDER BY A</code>, <code>ORDER BY A DESC</code>,
<code>ORDER BY A, B</code> or <code>ORDER BY A DESC, B DESC</code>.
With <code>ORDER BY A, B DESC</code> this index can only be used for ordering on the column <code>A</code>.
If columns are nullable, order of nulls is also important. Index on <code>(A ASC NULLS FIRST)</code> cannot be used for
<code>ORDER BY A ASC NULLS LAST</code>, but can be used for <code>ORDER BY A ASC NULLS FIRST</code> or
<code>ORDER BY A DESC NULLS LAST</code>.
When neither <code>NULLS FIRST</code> nor <code>NULLS LAST</code> is specified, a default is used, this default
is controlled by <a href="commands.html#set_default_null_ordering"><code>DEFAULT_NULL_ORDERING</code></a> setting.
</p><p>
For queries of the form <code>SELECT * FROM TEST GROUP BY ID ORDER BY ID</code>, the query plan includes the line
<code>/* group sorted */</code> to indicate there is no separate sorting required.
Expand Down
9 changes: 6 additions & 3 deletions h2/src/main/org/h2/bnf/context/DbContextRule.java
Expand Up @@ -89,7 +89,8 @@ public boolean autoComplete(Sentence sentence) {
best = quotedName;
bestSchema = schema;
}
} else if (s.isEmpty() || StringUtils.startsWithIgnoringCase(name, query) || StringUtils.startsWithIgnoringCase(quotedName, query)) {
} else if (s.isEmpty() || StringUtils.startsWithIgnoringCase(name, query)
|| StringUtils.startsWithIgnoringCase(quotedName, query)) {
if (s.length() < name.length()) {
sentence.add(name, name.substring(s.length()), type);
sentence.add(schema.quotedName + ".",
Expand All @@ -116,12 +117,14 @@ public boolean autoComplete(Sentence sentence) {
String name = table.getName();
String quotedName = StringUtils.quoteIdentifier(name);

if (StringUtils.startsWithIgnoringCase(query, name) || StringUtils.startsWithIgnoringCase("\"" + query, quotedName)) {
if (StringUtils.startsWithIgnoringCase(query, name)
|| StringUtils.startsWithIgnoringCase("\"" + query, quotedName)) {
if (best == null || name.length() > best.length()) {
best = name;
bestTable = table;
}
} else if (s.isEmpty() || StringUtils.startsWithIgnoringCase(name, query) || StringUtils.startsWithIgnoringCase(quotedName, query)) {
} else if (s.isEmpty() || StringUtils.startsWithIgnoringCase(name, query)
|| StringUtils.startsWithIgnoringCase(quotedName, query)) {
if (s.length() < name.length()) {
sentence.add(table.getQuotedName(),
table.getQuotedName().substring(s.length()),
Expand Down
6 changes: 4 additions & 2 deletions h2/src/main/org/h2/command/CommandRemote.java
Expand Up @@ -286,7 +286,8 @@ public BatchResult executeBatchUpdate(ArrayList<Value[]> batchParameters, Object
}
if (readGeneratedKeys) {
int columnCount = transfer.readInt();
ResultRemote remoteGeneratedKeys = new ResultRemote(session, transfer, objectId, columnCount, Integer.MAX_VALUE);
ResultRemote remoteGeneratedKeys = new ResultRemote(session, transfer, objectId,
columnCount, Integer.MAX_VALUE);
generatedKeys.add(remoteGeneratedKeys);
remoteGeneratedKeys.close();
}
Expand All @@ -310,7 +311,8 @@ public BatchResult executeBatchUpdate(ArrayList<Value[]> batchParameters, Object
autoCommit = transfer.readBoolean();
if (readGeneratedKeys) {
int columnCount = transfer.readInt();
ResultRemote remoteGeneratedKeys = new ResultRemote(session, transfer, objectId, columnCount, Integer.MAX_VALUE);
ResultRemote remoteGeneratedKeys = new ResultRemote(session, transfer, objectId,
columnCount, Integer.MAX_VALUE);
generatedKeys.add(remoteGeneratedKeys);
remoteGeneratedKeys.close();
}
Expand Down
2 changes: 1 addition & 1 deletion h2/src/main/org/h2/command/ddl/Analyze.java
Expand Up @@ -187,7 +187,7 @@ public static void analyzeTable(SessionLocal session, Table table, int sample, b
if (columnCount == 0) {
return;
}
Cursor cursor = table.getScanIndex(session).find(session, null, null);
Cursor cursor = table.getScanIndex(session).find(session, null, null, false);
if (cursor.next()) {
SelectivityData[] array = new SelectivityData[columnCount];
for (int i = 0; i < columnCount; i++) {
Expand Down
2 changes: 1 addition & 1 deletion h2/src/main/org/h2/command/dml/ScriptCommand.java
Expand Up @@ -474,7 +474,7 @@ private static <T extends DbObject> T[] sorted(Collection<T> collection, Class<T
private int generateInsertValues(int count, Table table) throws IOException {
PlanItem plan = table.getBestPlanItem(session, null, null, -1, null, null);
Index index = plan.getIndex();
Cursor cursor = index.find(session, null, null);
Cursor cursor = index.find(session, null, null, false);
Column[] columns = table.getColumns();
boolean withGenerated = false, withGeneratedAlwaysAsIdentity = false;
for (Column c : columns) {
Expand Down