# Use KeySelector.firstGreaterThan or just skip one KeyValue during iteration?

**URL:** <https://forums.foundationdb.org/t/use-keyselector-firstgreaterthan-or-just-skip-one-keyvalue-during-iteration/378>\
**Category:** Using FoundationDB\
**Created:** [May 8, 2018, 7:52am UTC](https://forums.foundationdb.org/t/use-keyselector-firstgreaterthan-or-just-skip-one-keyvalue-during-iteration/378 "2018-05-08T07:52:22Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![notxcain](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/notxcain/32/213_2.png) [@notxcain](https://forums.foundationdb.org/u/notxcain)\
**Post date:** [May 8, 2018, 7:52am UTC](https://forums.foundationdb.org/t/use-keyselector-firstgreaterthan-or-just-skip-one-keyvalue-during-iteration/378/1 "2018-05-08T07:52:22Z")

</div>

Hi! I wonder what is faster, using `tx.getKey` with `KeySelector.firstGreaterThan(begin)`, or just use `tx.getRange(begin, end)` and then skip one `KeyValue` during iteration?

---

<div class="post-metadata">

**Author:** ![panghy](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/panghy/32/19_2.png) [@panghy](https://forums.foundationdb.org/u/panghy)\
**Post date:** [May 8, 2018, 8:01am UTC](https://forums.foundationdb.org/t/use-keyselector-firstgreaterthan-or-just-skip-one-keyvalue-during-iteration/378/2 "2018-05-08T08:01:52Z")

</div>

Certainly getRange() with a KeySelector on begin rather than tx.getKey and then passing it to getRange (if that’s your ultimate goal). getKey() requires a round-trip.

---

<div class="post-metadata">

**Author:** ![notxcain](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/notxcain/32/213_2.png) [@notxcain](https://forums.foundationdb.org/u/notxcain)\
**Post date:** [May 8, 2018, 8:07am UTC](https://forums.foundationdb.org/t/use-keyselector-firstgreaterthan-or-just-skip-one-keyvalue-during-iteration/378/3 "2018-05-08T08:07:07Z")

</div>

My goal is to get a range from `Tuple.from("x", begin).pack` (exclusive) to `Tuple.from("x").end` (inclusive)

---

<div class="post-metadata">

**Author:** ![notxcain](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/notxcain/32/213_2.png) [@notxcain](https://forums.foundationdb.org/u/notxcain)\
**Post date:** [May 8, 2018, 8:10am UTC](https://forums.foundationdb.org/t/use-keyselector-firstgreaterthan-or-just-skip-one-keyvalue-during-iteration/378/4 "2018-05-08T08:10:18Z")

</div>

Oh, so its

```auto
getRange(
  KeySelector.firstGreaterThan(Tuple.from("x", begin).pack), 
  KeySelector.lastLessOrEqual(Tuple.from("x").end)
)

```

---

<div class="post-metadata">

**Author:** ![panghy](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/panghy/32/19_2.png) [@panghy](https://forums.foundationdb.org/u/panghy)\
**Post date:** [May 8, 2018, 8:11am UTC](https://forums.foundationdb.org/t/use-keyselector-firstgreaterthan-or-just-skip-one-keyvalue-during-iteration/378/5 "2018-05-08T08:11:35Z")

</div>

End is exclusive for getRange(), so you need to say firstGreaterThan() for the end if you want it to be inclusive.

---

<div class="post-metadata">

**Author:** ![notxcain](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/notxcain/32/213_2.png) [@notxcain](https://forums.foundationdb.org/u/notxcain)\
**Post date:** [May 8, 2018, 8:14am UTC](https://forums.foundationdb.org/t/use-keyselector-firstgreaterthan-or-just-skip-one-keyvalue-during-iteration/378/6 "2018-05-08T08:14:54Z")

</div>

Right. It works, thank you! 🙂 Still wrapping my head around keys and ranges.

---

<div class="post-metadata">

**Author:** ![alloc](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/alloc/32/9_2.png) [@alloc](https://forums.foundationdb.org/u/alloc)\
**Post date:** [May 9, 2018, 4:25am UTC](https://forums.foundationdb.org/t/use-keyselector-firstgreaterthan-or-just-skip-one-keyvalue-during-iteration/378/7 "2018-05-09T04:25:49Z")

</div>

As to your original question, efficiency wise, using the key selector or doing a range query and then skipping (as appropriate) is roughly the same. (Well, you don’t have send the bytes from the skipped key value pair over the wire, but disk I/O wise it’s the same and network I/O it’s almost always the same.) If you can use key selectors, that’s probably better (given that you save network I/O), but there aren’t behind-the-scenes savings at, say, the storage server level.

I the think a good rule of thumb is if you need to seek and then know the key that you landed on (which I find is usually the case), then you need to use `getRange`, and if you just need to know the value, then you can use `getKey`. One other caveat is that `getKey` doesn’t offer any kind of bounds checking while `getRange` can. (E.g., if you have a key `k` in a subspace `s` and want to find the first key greater than `k` but still in subspace `s`, you need to do something like `tr.getRange(KeySelector.firstGreaterThan(k), KeySelector.firstGreaterThan(s.range().end), limit=1)`.) Another rule of thumb that will probably get you most of the way there most of the time is to always use `getRange`.

EDIT: `getKey` to `getRange` to make my response almost make sense

---

<div class="post-metadata">

**Author:** ![ajbeamon](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/ajbeamon/32/13_2.png) [@ajbeamon](https://forums.foundationdb.org/u/ajbeamon)\
**Post date:** [May 9, 2018, 2:13pm UTC](https://forums.foundationdb.org/t/use-keyselector-firstgreaterthan-or-just-skip-one-keyvalue-during-iteration/378/8 "2018-05-09T14:13:29Z")

</div>

For what it’s worth, by default `getKey` is currently implemented by issuing a range read request to the storage server anyway. I think that if your transaction has disabled read your writes, though, it would issue a get key request instead.

---

<div class="post-metadata">

**Author:** ![panghy](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/panghy/32/19_2.png) [@panghy](https://forums.foundationdb.org/u/panghy)\
**Post date:** [May 9, 2018, 8:25pm UTC](https://forums.foundationdb.org/t/use-keyselector-firstgreaterthan-or-just-skip-one-keyvalue-during-iteration/378/9 "2018-05-09T20:25:10Z")

</div>

Ah, I mistook the original question as to whether to call getKey() first and pass it to getRange() vs. doing it just with getRange().

---

<div class="post-metadata">

**Author:** ![dave](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/dave/32/89_2.png) [@dave](https://forums.foundationdb.org/u/dave)\
**Post date:** [May 11, 2018, 12:48pm UTC](https://forums.foundationdb.org/t/use-keyselector-firstgreaterthan-or-just-skip-one-keyvalue-during-iteration/378/10 "2018-05-11T12:48:18Z")

</div>

> My goal is to get a range from Tuple.from(“x”, begin).pack (exclusive) to Tuple.from(“x”).end (inclusive)

If I understand you correctly, neither of the proposed solutions is right for this goal, because the key `Tuple.from("x", begin).pack` might not be present in the database!

What you want to do is to start your range read from the next _possible_ key, which is accomplished by adding a zero byte to the end of the key. I think this is available in many bindings with a name like “keyAfter()” but in a pinch you could write it yourself.

Since you say you want the end of the range to be inclusive, you should do that to the end key as well.

---

<div class="post-metadata">

**Author:** ![ajbeamon](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/ajbeamon/32/13_2.png) [@ajbeamon](https://forums.foundationdb.org/u/ajbeamon)\
**Post date:** [May 11, 2018, 2:45pm UTC](https://forums.foundationdb.org/t/use-keyselector-firstgreaterthan-or-just-skip-one-keyvalue-during-iteration/378/11 "2018-05-11T14:45:44Z")

</div>

> [@dave](#):
>
> What you want to do is to start your range read from the next possible key

Using a `firstGreaterThan` key selector as the begin argument to the range read accomplishes this, right? And using `firstGreaterThan(x)` at the end means the first key excluded is the next key after `x`, so it would be inclusive of `x`.

---

<div class="post-metadata">

**Author:** ![dave](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/dave/32/89_2.png) [@dave](https://forums.foundationdb.org/u/dave)\
**Post date:** [May 11, 2018, 3:12pm UTC](https://forums.foundationdb.org/t/use-keyselector-firstgreaterthan-or-just-skip-one-keyvalue-during-iteration/378/12 "2018-05-11T15:12:34Z")

</div>

@ajbeamon

Yes, you are right, that is exactly the same. My bad. And maybe the implementation actually optimizes getRange(firstGreater(x),…) to getRange(keyAfter(x),…) anyway, so that there is no efficiency difference?

---

<div class="post-metadata">

**Author:** ![KrzysFR](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/krzysfr/32/43_2.png) [@KrzysFR](https://forums.foundationdb.org/u/KrzysFR)\
**Post date:** [May 11, 2018, 4:21pm UTC](https://forums.foundationdb.org/t/use-keyselector-firstgreaterthan-or-just-skip-one-keyvalue-during-iteration/378/13 "2018-05-11T16:21:48Z")

</div>

`keyAfter()` seems to only be defined by the flow binding:

> <https://github.com/apple/foundationdb/blob/ca720e15403bbe05a28a02b67d54b84bed9e09e3/fdbclient/FDBTypes.h#L264>

Is this something that is frequent enough to justify being exposed by other bindings?

What about `keyBetween(..)` which seems to only be used by the StorageMetrics actor ?

---

<div class="post-metadata">

**Author:** ![ajbeamon](https://sea1.discourse-cdn.com/foundationdb/user_avatar/forums.foundationdb.org/ajbeamon/32/13_2.png) [@ajbeamon](https://forums.foundationdb.org/u/ajbeamon)\
**Post date:** [May 12, 2018, 12:34am UTC](https://forums.foundationdb.org/t/use-keyselector-firstgreaterthan-or-just-skip-one-keyvalue-during-iteration/378/14 "2018-05-12T00:34:14Z")

</div>

I think it’s a useful utility function that wouldn’t be out of place in a binding, particularly if appending a null byte to a key is syntactically ugly. It also is perhaps a little more obvious to the reader what it’s going compared to doing the append by hand.
