Improve backup export perf by using better batching.

This commit is contained in:
Greyson Parrelli
2024-10-24 13:46:13 -04:00
parent ec736afde4
commit ebca386dcb
9 changed files with 252 additions and 142 deletions

View File

@@ -154,6 +154,17 @@ object SqlUtil {
}.toTypedArray()
}
@JvmStatic
fun buildArgs(objects: Collection<Any?>): Array<String> {
return objects.map {
when (it) {
null -> throw NullPointerException("Cannot have null arg!")
is DatabaseId -> it.serialize()
else -> it.toString()
}
}.toTypedArray()
}
@JvmStatic
fun buildArgs(argument: Long): Array<String> {
return arrayOf(argument.toString())
@@ -290,6 +301,20 @@ object SqlUtil {
}
}
/**
* A convenient way of making queries that are _equivalent_ to `WHERE [column] IN (?, ?, ..., ?)`
* Under the hood, it uses JSON1 functions which can both be surprisingly faster than normal (?, ?, ?) lists, as well as removes the [MAX_QUERY_ARGS] limit.
* This means chunking isn't necessary for any practical collection length.
*/
@JvmStatic
fun buildFastCollectionQuery(
column: String,
values: Collection<Any?>
): Query {
require(!values.isEmpty()) { "Must have values!" }
return Query("$column IN (SELECT e.value FROM json_each(?) e)", arrayOf(jsonEncode(buildArgs(values))))
}
/**
* A convenient way of making queries in the form: WHERE [column] IN (?, ?, ..., ?)
*
@@ -453,6 +478,11 @@ object SqlUtil {
return null
}
/** Simple encoding of a string array as a json array */
private fun jsonEncode(strings: Array<String>): String {
return strings.joinToString(prefix = "[", postfix = "]", separator = ",") { "\"$it\"" }
}
class Query(val where: String, val whereArgs: Array<String>) {
infix fun and(other: Query): Query {
return if (where.isNotEmpty() && other.where.isNotEmpty()) {

View File

@@ -170,6 +170,22 @@ public final class SqlUtilTest {
assertTrue(results.isEmpty());
}
@Test
public void buildFastCollectionQuery_single() {
SqlUtil.Query updateQuery = SqlUtil.buildFastCollectionQuery("a", Arrays.asList(1));
assertEquals("a IN (SELECT e.value FROM json_each(?) e)", updateQuery.getWhere());
assertArrayEquals(new String[] { "[\"1\"]" }, updateQuery.getWhereArgs());
}
@Test
public void buildFastCollectionQuery_multiple() {
SqlUtil.Query updateQuery = SqlUtil.buildFastCollectionQuery("a", Arrays.asList(1, 2, 3));
assertEquals("a IN (SELECT e.value FROM json_each(?) e)", updateQuery.getWhere());
assertArrayEquals(new String[] { "[\"1\",\"2\",\"3\"]" }, updateQuery.getWhereArgs());
}
@Test
public void buildCustomCollectionQuery_single_singleBatch() {
List<String[]> args = new ArrayList<>();