Skip to content
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

Cache unique values when creating features #9203

Merged
merged 20 commits into from Feb 21, 2019

Conversation

elpaso
Copy link
Contributor

@elpaso elpaso commented Feb 19, 2019

Cache unique values when creating features

Fixes #21305 - pasting features is very slow

Aggressively optimize createFeature for speed
and introduces createFeatures for bulk creation.

Fixes qgis#21305 - pasting features is very slow

Aggressively optimize createFeature for speed
and introduces createFeatures for bulk creation.
@elpaso
Copy link
Contributor Author

elpaso commented Feb 19, 2019

@nyalldawson @m-kuhn I'd appreciate your review on this one.

Speed gain is really huge and it makes pasting features usable again.

@m-kuhn
Copy link
Member

m-kuhn commented Feb 19, 2019

I like the idea

The only thing I'm not sure about is if it's worth mentioning a performance factor, there's probably a linear dependency between the speed gain and the number of features :)

@elpaso
Copy link
Contributor Author

elpaso commented Feb 19, 2019

@m-kuhn thanks for the review, how do you feel about backporting, is that ok?

@m-kuhn
Copy link
Member

m-kuhn commented Feb 19, 2019

I would give it a considerable amount of testing time before backporting given that there's a risk of side effects.

@gioman
Copy link
Contributor

gioman commented Feb 19, 2019

I would give it a considerable amount of testing time before backporting given that there's a risk of side effects.

@m-kuhn I will do my best to test it, anyway this possibly solve a very bad regression (and hopefully also fixes the other issue about opening time of attribute tables with many columns, that is QGIS 3 has become unbearably slow).

Co-Authored-By: elpaso <elpaso@itopen.it>
Co-Authored-By: elpaso <elpaso@itopen.it>
@elpaso
Copy link
Contributor Author

elpaso commented Feb 19, 2019

@m-kuhn sql is QByteArray

@m-kuhn
Copy link
Member

m-kuhn commented Feb 19, 2019

oops

@m-kuhn
Copy link
Member

m-kuhn commented Feb 19, 2019

What I wonder more is if it's appropriate to trigger a createFeature() on every paste operation.

Shouldn't the logic be

  • If a pasted feature misses an attribute (really misses, not if it's NULL) then get a default value for this attribute
  • Then check unique constraints and if some unique constraints fail, try to get a unique attribute

Or is this not the same kind of pasting we are talking about?

@elpaso
Copy link
Contributor Author

elpaso commented Feb 19, 2019

What I wonder more is if it's appropriate to trigger a createFeature() on every paste operation.

Shouldn't the logic be

* If a pasted feature misses an attribute (really misses, not if it's NULL) then get a default value for this attribute

* Then check unique constraints and if some unique constraints fail, try to get a unique attribute

Or is this not the same kind of pasting we are talking about?

I'm not sure I follow you: this is exactly what happens inside the monster method createFeature/s: all constraints are checked, all defaults are evaluated and the last step tries to create a unique value if the unique constraint is still not honored.

I'm currently working on a fix for this last step: we should use the cached unique values instead of fetching from the provider (because the provider does not have all the values from the possibly previously other created features).

Btw, I'm happy to talk/chat to you about this: maybe easier to explain.

@elpaso
Copy link
Contributor Author

elpaso commented Feb 19, 2019

@m-kuhn see my last commit for the unique values generation (now using the cached unique values) and the new test that failed with the previous implementation.

v = attributes.value( idx );
}
// 3. provider side default value clause
// note - not an else if deliberately. Users may return null from a default value expression to fallback to provider defaults
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really want that? NULL to fallback to provider defaults... different discussion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually the check below is for isValid() and the comment here says NULL

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, different discussion (that we need to do sooner or later), I called this monster method for a reason, I don't entirely get the logic here since there are a lot of different permutations of use cases.

@m-kuhn
Copy link
Member

m-kuhn commented Feb 20, 2019

@elpaso I see how it works now, looks reasonable. Very good!
I just left some comments which I think already applied to the code before, would be good to get @nyalldawson 's eyes there too, if I'm not mistaken he's the original author of that.

Co-Authored-By: elpaso <elpaso@itopen.it>
@nirvn
Copy link
Contributor

nirvn commented Feb 20, 2019

Is the plan for this to be merged into 3.6.0, or is it better to aim at 3.6.1 to give it more testing time?

@elpaso
Copy link
Contributor Author

elpaso commented Feb 20, 2019

@nirvn I'd merge into 3.6: there is quite a good test coverage on this area and without this patch pasting a bunch of features with a "slow" provider makes QGIS completely unresponsive for minutes.

I removed the backporting tag, but if it was my decision I would backport it.

@m-kuhn
Copy link
Member

m-kuhn commented Feb 20, 2019

I agree, merging for 3.6.0 is a good idea, it looks "safe enough" and more testing is welcome. For backporting I think the question is not if but when.

@nirvn
Copy link
Contributor

nirvn commented Feb 20, 2019

Ok. If you guys think it's safe enough, I'm happy with that :)

isValid is not enough because fields are initialized with
QVariant(field.type()) which is valid but null.

Fixes qgis#21304

With test
@elpaso
Copy link
Contributor Author

elpaso commented Feb 20, 2019

@m-kuhn is this what you meant with checking for nulls? bf1575f

I added a test for bug https://issues.qgis.org/issues/21304

@m-kuhn
Copy link
Member

m-kuhn commented Feb 20, 2019

Codewise, v.isNull() implicitly also checks for !v.isValid() so the extra check there is no longer required if this change is done.

However, I was more questioning this functionality in general. I.e. I believe a QGIS configured default value should be able to overwrite a database default value with a NULL value.

Maybe we need to add a new INVALID value that can be used by default values so we no longer abuse NULL.

But I'd really appreciate a statement by @nyalldawson concerning this before deciding for a path.

@elpaso elpaso merged commit 17280c3 into qgis:master Feb 21, 2019
@elpaso elpaso deleted the bugfix-21305-paste-slow-no-provider branch February 21, 2019 07:31
@gioman
Copy link
Contributor

gioman commented Feb 21, 2019

For backporting I think the question is not if but when.

so this will not be backported? I understand playing safe but please also consider the bad regression (for a pretty common operation) we will eventually ship into the release that will put to bed 2.18.

@m-kuhn
Copy link
Member

m-kuhn commented Feb 21, 2019

so this will not be backported?

on the contrary, it will be backported when we have enough test results to be sure it doesn't introduce any regressions.

@gioman
Copy link
Contributor

gioman commented Feb 21, 2019

on the contrary,

sorry I expressed myself badly... I was thinking (in time) for the upcoming release.

@m-kuhn
Copy link
Member

m-kuhn commented Feb 21, 2019

@gioman @elpaso do you feel confident for an express backport on this?
I'm not putting a veto on it, just thought another couple of weeks for testing this might be good, but if you feel it's appropriate to move ahead, please proceed.

@nyalldawson
Copy link
Collaborator

My vote would go to playing it safe and waiting till 3.4.6 here -- I understand it's a major regression, but this code is quite complex and there's a chance a worse regression may have been introduced!

@gioman
Copy link
Contributor

gioman commented Feb 21, 2019

My vote would go to playing it safe and waiting till 3.4.6 here -- I understand it's a major regression, but this code is quite complex and there's a chance a worse regression may have been introduced!

@nyalldawson @elpaso @m-kuhn I understand, no worries. Thanks everyone for the great bug fixing effort!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants