【发布时间】:2018-09-27 18:13:16
【问题描述】:
我需要找到索引唯一属性整数值的最大值。
节点有索引:
- 在 (n:Transaction) 上创建约束断言 n.id 是唯一的
我试过查询:
- MATCH (n:Transaction) 返回 n.id ORDER BY n.id DESC LIMIT 1
- MATCH (n:Transaction) RETURN max(n.id)
两个查询都经过整个扫描而不是使用索引。
如何优化查询以快速找到最大值?
【问题讨论】:
我需要找到索引唯一属性整数值的最大值。
节点有索引:
我试过查询:
两个查询都经过整个扫描而不是使用索引。
如何优化查询以快速找到最大值?
【问题讨论】:
使用索引来优化ORDER BY 查询的能力是现有的issue,并计划在 neo4j 3.5 中实现——这应该会在今年年底推出( 2018)。
[编辑]
同时,为避免扫描所有 Transaction 节点,如果您知道最大id 的良好min 值,则可以尝试执行范围查询。例如,如果最后一个已知的最大“id”是 10000:
MATCH (t:Transaction)
WHERE t.id >= 10000
RETURN node.id AS id
ORDER BY id DESC
LIMIT 1
以上查询将使用索引快速定位id值>=最小值。
【讨论】:
由于@cybersam 提到的已知 Neo4j 的问题,我在客户端 (java) 端实施了临时解决方法来执行二进制搜索。它通过多达 32 个单节点查询找到最大值,与原始单次调用超过一亿个节点的数据大小相比,运行时间减少到亚秒级。
public int getLastTransactionId() {
//return getInteger("MATCH (n:Transaction) RETURN n.id ORDER BY n.id DESC LIMIT 1").orElse(0);
//Neo4j currently having issues with using inexes for ORDER or MAX
//do binary search as a workaround
return findMax("MATCH (n:Transaction {id:{id}}) RETURN n.id");
}
public int findMax(String query) {
int minVal = 0;
int maxVal = Integer.MAX_VALUE;
while (minVal < maxVal) {
int middle = (int) ((1L + minVal + maxVal) / 2);
OptionalInt o = getInteger(query, Values.parameters("id", middle));
log.debug("min:{}, max:{}, middle:{}, o:{}", minVal, maxVal, middle, o);
if (o.isPresent()) {
minVal = middle;
} else {
maxVal = middle - 1;
}
}
return maxVal;
}
【讨论】: