I have a fairly involved query that gets top scores for players in a leaderboard used by multiple apps (games). Each player can have multiple scores, but I am only pulling their top score.
Using 4.5 beta.
The query looks like this:
select
max([score,meta(scorebeast).id])[0] as score,
max([score,meta(scorebeast).id])[1] as scoreId,
max([score,date])[1] as date,
max([score,nick])[1] as nick
from scorebeast
where score is not null and app = 'some_game' and meta(scorebeast).id like 'score_%'
group by userId
order by score desc, date asc
limit 10 offset 100
I am currently getting execution time of 6 seconds (improvement from 12 seconds after creating basic indexes), but I am wondering if this can be pushed further.
How can I improve this query?
explain here:
[
{
"plan": {
"#operator": "Sequence",
"~children": [
{
"#operator": "Sequence",
"~children": [
{
"#operator": "IntersectScan",
"scans": [
{
"#operator": "IndexScan",
"index": "score_idx",
"index_id": "22237429400cc486",
"keyspace": "scorebeast",
"namespace": "default",
"spans": [
{
"Range": {
"Inclusion": 0,
"Low": [
"null"
]
}
}
],
"using": "gsi"
},
{
"#operator": "IndexScan",
"index": "app_idx",
"index_id": "b58177828b6774d0",
"keyspace": "scorebeast",
"namespace": "default",
"spans": [
{
"Range": {
"High": [
"\"some_game\""
],
"Inclusion": 3,
"Low": [
"\"some_game\""
]
}
}
],
"using": "gsi"
},
{
"#operator": "IndexScan",
"index": "scorebeast-primary-index",
"index_id": "351355ff755686da",
"keyspace": "scorebeast",
"namespace": "default",
"spans": [
{
"Range": {
"High": [
"\"scorf\""
],
"Inclusion": 1,
"Low": [
"\"score\""
]
}
}
],
"using": "gsi"
}
]
},
{
"#operator": "Parallel",
"~child": {
"#operator": "Sequence",
"~children": [
{
"#operator": "Fetch",
"keyspace": "scorebeast",
"namespace": "default"
},
{
"#operator": "Filter",
"condition": "((((`scorebeast`.`score`) is not null) and ((`scorebeast`.`app`) = \"some_game\")) and ((meta(`scorebeast`).`id`) like \"score_%\"))"
},
{
"#operator": "InitialGroup",
"aggregates": [
"max([(`scorebeast`.`score`), (`scorebeast`.`date`)])",
"max([(`scorebeast`.`score`), (`scorebeast`.`nick`)])",
"max([(`scorebeast`.`score`), (meta(`scorebeast`).`id`)])"
],
"group_keys": [
"(`scorebeast`.`userId`)"
]
}
]
}
},
{
"#operator": "IntermediateGroup",
"aggregates": [
"max([(`scorebeast`.`score`), (`scorebeast`.`date`)])",
"max([(`scorebeast`.`score`), (`scorebeast`.`nick`)])",
"max([(`scorebeast`.`score`), (meta(`scorebeast`).`id`)])"
],
"group_keys": [
"(`scorebeast`.`userId`)"
]
},
{
"#operator": "FinalGroup",
"aggregates": [
"max([(`scorebeast`.`score`), (`scorebeast`.`date`)])",
"max([(`scorebeast`.`score`), (`scorebeast`.`nick`)])",
"max([(`scorebeast`.`score`), (meta(`scorebeast`).`id`)])"
],
"group_keys": [
"(`scorebeast`.`userId`)"
]
},
{
"#operator": "Parallel",
"~child": {
"#operator": "Sequence",
"~children": [
{
"#operator": "InitialProject",
"result_terms": [
{
"as": "score",
"expr": "(max([(`scorebeast`.`score`), (meta(`scorebeast`).`id`)])[0])"
},
{
"as": "scoreId",
"expr": "(max([(`scorebeast`.`score`), (meta(`scorebeast`).`id`)])[1])"
},
{
"as": "date",
"expr": "(max([(`scorebeast`.`score`), (`scorebeast`.`date`)])[1])"
},
{
"as": "nick",
"expr": "(max([(`scorebeast`.`score`), (`scorebeast`.`nick`)])[1])"
}
]
}
]
}
}
]
},
{
"#operator": "Order",
"limit": "10",
"offset": "100",
"sort_terms": [
{
"desc": true,
"expr": "`score`"
},
{
"expr": "`date`"
}
]
},
{
"#operator": "Offset",
"expr": "100"
},
{
"#operator": "Limit",
"expr": "10"
},
{
"#operator": "FinalProject"
}
]
},
"text": "\nselect \n max([score,meta(scorebeast).id])[0] as score,\n max([score,meta(scorebeast).id])[1] as scoreId,\n max([score,date])[1] as date,\n max([score,nick])[1] as nick\n from scorebeast\n where score is not null and app = 'some_game' and meta(scorebeast).id like 'score_%'\n group by userId\n order by score desc, date asc\n limit 10 offset 100"
}
]