Two equivalent queries, one is slow and the other one is fast

Hello again.

Not sure if this is expected or it is a bug.

As I understand, the following two queries should be equivalent

slow_q2009(func: has(year)) @filter(eq(year, 2009)) {
        count(uid)
}
fast_q2009(func: eq(year, 2009)) {
        count(uid)
}

However slow_q2009 takes almost 9 seconds while fast_q2009 takes only 150ms.

Does dgraph do any kind of query execution plan and query optimization? Or am I assuming wrongly that both queries are equivalent? Should I report it as a bug?

They are different as far as I can tell. has func at root param is a very wide query. It runs throughout the whole DB searching for “year”. As for the second just uses the index table. That’s why it is faster.

The execution order of a query is:
1 - The root query params.
2 - The root filters.
3 - The nested blocks following the same order.

For Has func, I personally recommend to use as a second param (I mean, in the filter) or in nested levels. The has func is like this cuz sometimes some edges can be empty(It would not be indexed). So It would probably be interesting to improve the has strategy. To use the index table if it exists. Or create another type of has func that takes indexing into consideration.

But I’m just guessing in the possible indexing part, I don’t know exactly how the Has function works under the hood, in the hypothesis of making it work with indexing. But it would be worth trying an issue for that. (Or see if there are any already).

Cheers.

PS.

Yeah, I think so. I think we have it in the 2019 Roadmap (and probably in the 2020 by now).

Would a root level type(Foo) have similar performance concerns as has(predicate)? For example:

query(func: type(User)) @filter(eq(age, 30)) {
  count(uid)
}

Would it be better to swap the eq and type?

Type func is similar to:

{
query(func: eq(dgraph.type, "User")) @filter(eq(age, 30)) {
  count(uid)
}

It has its own indexing approach.

1 Like