While this seems like a really simple problem, the only solution I've come up with is below, any suggestions for something less ugly with lower time complexity?
My application is in Java and is retrieving with a MS-sql DB using skife.jdbi
.
Say I have a Table
with columns A
, B
, and C
where A
and B
form a primary key. And I want to retrieve C
given a particularly A
and B
. This is easily accomplished. But what if I my throughput requirement is very high, so I want to make these Select
statements in batches. I end up with something like the below:
Given a Set
of Objects
with values A
and B
, I iterate the List compiling all the values of A
and B
. I then run a query like SELECT A, B, C FROM tbl WHERE A IN :listOfAs AND B IN :listOfBs
. I then iterate the results of the query, matching a result to the original object by comparing the A
and B
value. Which all sounds reasonable, but the code ends up looking like the below, which seems ugly and suboptimal?
class MyObject {
String A;
String B;
String C;
Object otherData;
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (!(other instanceof MyObject)) {
return false;
} else {
return A.equals(other.A) && B.equals(other.B);
}
}
@Override
public int hashCode() {
return 31 * A.hashCode() + B.hashCode();
}
}
// populates the of objects with their proper C value
void retrieveC(Set<MyObject> input) {
Set<String> aValues = new HashSet<>();
Set<String> bValues = new HashSet<>();
for (MyObject object : input) {
aValues.add(object.A);
bValues.add(object.B);
}
// the dao executes the query mentioned above, and returns a Set of
// MyObject instances with members A, B, and C populated from the results.
// Any results that do not contain a value for A, B, and C (which
// shouldn't exit) are filtered out by the dao.
Set<MyObject> results = dao.selectC(aValues, bValues);
// ewww... O(n^2)
for (MyObject object : input) {
boolean resultFound = false;
for (MyObject result : results) {
if (object.equals(result)) {
object.C = result.C;
resultFound = true;
break;
}
}
if (!resultFound) {
// handle this case
}
}
}