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

Optimize number of transactions sent in refresh #14670

Merged

Conversation

Ladas
Copy link
Contributor

@Ladas Ladas commented Apr 6, 2017

Do not do a blank transaction if the record hasn't changed, because it causes extra 2 queries, transaction BEGIN and END. And wrap updating&deleting in 1 big transaction. Doing transaction per update is expensive, since we do BEGIN, update, END, so 3 queries per one updateand the same for delete. With remote DB, this will add a lot of processing time.

Example:

ca = CustomAttribute.first; ca1 = CustomAttribute.second

# This does 1 BEGIN and COMMIT query for all updates inside
ActiveRecord::Base.transaction { ca.update_attributes!(:section => "labels1"); ca1.update_attributes!(:section => "labels1") }

# This does 1 BEGIN and COMMIT for each update
ca.update_attributes!(:section => "labels1"); ca1.update_attributes!(:section => "labels1")

Partially fixes:
https://bugzilla.redhat.com/show_bug.cgi?id=1436176


The performance improvements are mainly visible with second+ refresh, since creating objects by association.push(new_records) is already using 1 transaction for many records created. We are just optimizing that number of transaction also for nested objects created.

** stats are being measured with applied PRs #13594 #14542

Performance improvements, given we are saving 290k object to the DB during refresh:

refresh number of queries done during refresh time on a local db time on a remote db with ~5ms ping
1st refresh before 421 146 ~18min ~53min
1st refresh after 385 162 ~18min ~50min
improvement 9.3% smaller 0% faster 6% faster
2nd+ refresh before 786 380 ~14min ~80min
2nd+ refresh after 135 198 ~7min ~18min
improvement 481% smaller 100% faster 344% faster

** the second refresh is measured when nothing is updated (the same VCR). But this PR brings a big speedup when we do update/delete records, since we do only 1 query per updated/deleted item, not 3 queries, like we did before this PR.

blomquisg and others added 3 commits April 6, 2017 15:12
Allow save inventory to skip starting a transaction if the record being
saved was not actually changed by the provider's inventory data.

VMs and Storages still directly call `update_attributes!`.  At the
moment, it doesn't seem like those object counts are limiting factors.
If that changes, we can look at applying the same change there.
Do not do a blank transaction if the record hasn't changed,
becaiuse it causes extra 2 queries, transaction BEGIN and END
Wrap updating&deleting in 1 big transaction. Doing transaction per
update is expensive, since we do BEGIN, update, END, so 3 queries
per one updateand the same for delete. With remote DB, this will
add a lot of processing time.
@blomquisg
Copy link
Member

I own a commit in this PR, so assigning over to @Fryguy

deletes.delete(found) unless deletes.blank?
end
found
end

def update_attributes!(ar_model, attributes, remove_keys)
ar_model.assign_attributes(attributes.except(*remove_keys))
ar_model.save! if ar_model.changed?
Copy link
Member

Choose a reason for hiding this comment

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

Can you put a note here with a reference to the upstream issue? Maybe something like

# HACK: Avoid empty BEGIN/COMMIT pair until fix is made for https://github.com/rails/rails/issues/17937

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

@Fryguy
Copy link
Member

Fryguy commented Apr 6, 2017

@Ladas Can you show some statistic on improvement? Matrix of Remote DB/Local DB x Initial refresh/second refresh

type = association.proxy_association.reflection.name
_log.info("[#{type}] Deleting #{log_format_deletes(deletes)}")
disconnect ? deletes.each(&:disconnect_inv) : association.delete(deletes)
end
Copy link
Member

Choose a reason for hiding this comment

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

If there are no deletes, doesn't this introduce an empty BEGIN/COMMIT pair because of the transaction? Instead, is it better to do

  unless deletes.blank?
    ActiveRecord::Base.transaction do
      type = association.proxy_association.reflection.name
      _log.info("[#{type}] Deleting #{log_format_deletes(deletes)}")
      disconnect ? deletes.each(&:disconnect_inv) : association.delete(deletes)
    end
  end

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch, will fix it. Though this will not affect the stats much, due to the nested nature.

@Fryguy
Copy link
Member

Fryguy commented Apr 7, 2017

Overall looks good...couple of minor things.

Add a comment about rails issue causing nil transaction
Do a transaction only if there are items to be deleted, to
avoind empty transactions.
@miq-bot
Copy link
Member

miq-bot commented Apr 7, 2017

Checked commits Ladas/manageiq@8ad0ac2~...2b2862e with ruby 2.2.6, rubocop 0.47.1, and haml-lint 0.20.0
1 file checked, 0 offenses detected
Everything looks good. ⭐

@Ladas
Copy link
Contributor Author

Ladas commented Apr 7, 2017

@Fryguy I've fixed the minor things and added the table showing the performance improvement in %

Copy link
Member

@kbrock kbrock left a comment

Choose a reason for hiding this comment

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

👍 LGTM

@Fryguy Fryguy merged commit 73555f3 into ManageIQ:master Apr 7, 2017
@Fryguy Fryguy added this to the Sprint 58 Ending Apr 10, 2017 milestone Apr 7, 2017
@Fryguy
Copy link
Member

Fryguy commented Apr 7, 2017

@simaishi euwe backport is at #14674

@dmetzger57
Copy link
Contributor

@miq-bot add_labels performance

simaishi pushed a commit that referenced this pull request Apr 7, 2017
…sent_in_refresh

Optimize number of transactions sent in refresh
(cherry picked from commit 73555f3)
@simaishi
Copy link
Contributor

simaishi commented Apr 7, 2017

Fine backport details:

$ git log -1
commit 130b0a6a6bd2a53fa35f507fb95a95818f33a522
Author: Jason Frey <fryguy9@gmail.com>
Date:   Fri Apr 7 11:46:20 2017 -0400

    Merge pull request #14670 from Ladas/optimize_number_of_transactions_sent_in_refresh
    
    Optimize number of transactions sent in refresh
    (cherry picked from commit 73555f3fe14869fb35e274dbf3e6eb1a8f85d3d3)

@simaishi simaishi removed the fine/yes label Apr 7, 2017
@simaishi
Copy link
Contributor

Backported to Euwe via #14674

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

Successfully merging this pull request may close these issues.

8 participants