-
-
Notifications
You must be signed in to change notification settings - Fork 358
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve database performance #3741
Improve database performance #3741
Conversation
make use of the fact that node table basically contains node geometry
app/src/main/java/de/westnordost/streetcomplete/data/osm/geometry/ElementGeometryTable.kt
Outdated
Show resolved
Hide resolved
Tests are added, so I marked the PR as ready. I tested the database upgrade by installing a current version of SC and downloaded some area in addition to initial scan. Then I installed a build from this PR and SC worked as expected when opening a few quests. Is that enough? Upgrading the DB gave a black screen at start, about 15 seconds for a 20 MB database (14 MB after upgrade) on my S4 mini. This is not great, but I would expect the average phone to be considerably faster than mine. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! I am going to attempt some more optimizations on top of this branch so you can leave the processing of my comments to me
app/src/main/java/de/westnordost/streetcomplete/data/osm/geometry/ElementGeometryDao.kt
Outdated
Show resolved
Hide resolved
.../androidTest/java/de/westnordost/streetcomplete/data/osm/geometry/RelationGeometryDaoTest.kt
Outdated
Show resolved
Hide resolved
app/src/androidTest/java/de/westnordost/streetcomplete/data/osm/geometry/WayGeometryDaoTest.kt
Outdated
Show resolved
Hide resolved
app/src/main/java/de/westnordost/streetcomplete/data/osm/mapdata/ElementDao.kt
Outdated
Show resolved
Hide resolved
|
||
fun getAll(bbox: BoundingBox): List<Node> { | ||
return db.query(NAME, where = inBoundsSql(bbox)) { cursor -> | ||
Node( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
duplication of creating Node from cursor, same with ElementGeometryEntry
… know anything of ElementKey
that data structure was never intended to be public. The helper function is shorter and about as performant
So is there anything left for me, or are you doing the rest? |
I did the rest. However, I created the branch However, I am not sure about performance. You still have this nice test setup, don't you? Could you test / compare the performance of |
I remember it was faster, but returned fewer elements: #2803 (comment) Is this still the case? Then I'll try make the testing a bit more exhaustive and compare the number of returned elements as well. |
Yes, it is deliberate that it returns less elements. This is how the OSM API works. It returns all elements who have at least one node inside the given bbox. Current StreetComplete behavior is that it returns all elements whose bbox intersect with the bbox given. E.g. imagine a bicycle route relation that goes from the town center out to the suburbs in the North-West. The bbox of this relation would be quite large, so the route relation would be included in every bbox-query between the center and anywhere in the north or the west or northwest. When querying the OSM API, the route relation would only be included if a node of a way to which it refers is included in the bbox. |
Thank you for the link to #2803. I've read it again and see there is the issue with #2803 (comment) But on the other hand, we already add a padding of 20m to each side of the bbox plus it is only used for fuzzy filters to not ask for certain elements. Fuzzy filters are fuzzy anyways, it's OK if the user instead answers e.g. "cycleway displayed separately on map" because one might argue that this info was missing anyway. |
It seems like the main performance problem comes from fetching relations that intersect the bbox. However, the use case in #2803 (comment) seems like it applies primarily to ways. Would it make sense to use the current SC approach (show if intersecting) for ways and the osmapi approach (show only if a node is contained) for relations? Or is that not possible for technical reasons? |
Technical reasons that speak against this is that it is more complex (more code, possibly hacky-looking code) and looks inconsistent, plus is inconsistent with the OSM API. For me, this is reason enough to not consider it. |
In my opinion, performance optimizations are possibly the best justification for hacky code. I imagine an interface like fun fetchByBbox(bbox: Bbox, includeIntersectingWays: Boolean = false, includeInteresctingRelations: Boolean = false) Under the hood, the initial, cleaner implementation would perform a fetch-by-bbox query that works like the osm api, then separate call(s) to find intersecting ways or relations. I suspect doing separate calls would be a performance hit, although I'm not sure by how much (maybe still better than always looking for relations). Then we could decide whether combining the queries would be worth the messier code. But anyway, I do not have a very strong opinion. Just wanted to share the idea. If your opinion remains the same, no need to respond. |
By a very short look, |
Thank you! Nice, so it is not slower, probably actually a little faster (if only because it returns less elements, who knows). So, can you merge it into this branch and I merge this branch into master? Also, compared to current situation, what would be the speed gain, overall in %? Would be nice to have a % for the changelog |
implement changes from "fetch-by-bbox" branch
Comparing to the current state:
|
130%?! Wow, I completely underestimated the difference this makes.... how? Edit: Yeah, a primary key is automatically an index as far as I know - |
My test showed that Lines 86 to 90 in ed59421
was quite slow (500 ms+). When I replaced the queryIn by querying a single column with my hacky single index, ElementGeometryDao.getAllEntries(keys) was a lot faster. That's what started trying the optimizations on the normal database, because in that query there is no R-tree index involved.
|
Aaahh, right. This is because it is actually not really supported by SQLite, queryIn is a workaround: |
ElementGeometryDao
is optimized in this PR, see #3609 (comment) for performance comparison with current version.The element geometry table is split into separate tables for ways and relations to avoid slow
queryIn
ingetAllEntries(keys)
.Nodes do not have a separate geometry table, as nodes have a simple point geometry that can be created from the node position.
A spatial index is added to
NodeTable
, and some functions for querying nodes inside a bbox are added toNodeDao
(equivalents to functions inElementGeometryDao
).MapDataController.getMapDataWithGeometry
makes use of the the new table layout by not querying node geometry and data separatly, instead point geometry is created from node positions.Still a draft, because database upgrade is missing and tests have not been updated yet.